c++ vs. java... was hat zukunft



  • CStoll schrieb:

    (und woher weiß dein refactore-Script, welche Methoden nun in das Point-Interface gepackt werden sollen?)

    das ist von der IDE abhängig, z.b. einfach die methoden auswählen, dann 'extract interface' oder sowas anklicken, dann den namen eines neuen interfaces eingeben oder den eines bestehenden auswählen und fertig.

    CStoll schrieb:

    (ja, ich kann einer Klasse einen Copy-Ctor und eine Clone()-Methode spendieren - aber ich kann niemanden dazu zwingen, diese Methoden zu verwenden, wenn er Objekte zuweist (oder etwa doch?)).

    z.b. könnte man alle anderen konstruktoren 'protected' machen und den copy-construktor 'public', dann kann ausserhalb des packages nur der copy-constructor aufgerufen werden.

    CStoll schrieb:

    Bei einer ausgewachsenen Klasse ist das Referenzverhalten durchaus sinnvoll, bei einer Hilfsklasse ist Kopiersemantik angebrachter.

    ich finde nicht, dass man es daran festmachen sollte.
    kopieren würde ich nur, wenn es sinnvoll ist oder sich nicht vermeiden lässt, sonst nicht.
    🙂



  • pale dog schrieb:

    CStoll schrieb:

    (ja, ich kann einer Klasse einen Copy-Ctor und eine Clone()-Methode spendieren - aber ich kann niemanden dazu zwingen, diese Methoden zu verwenden, wenn er Objekte zuweist (oder etwa doch?)).

    z.b. könnte man alle anderen konstruktoren 'protected' machen und den copy-construktor 'public', dann kann ausserhalb des packages nur der copy-constructor aufgerufen werden.

    Und kann ich auf diese Weise auch die (in Java normale) Referenz-Zuweisung ala 'MyHelper x = y;' verbieten lassen?

    CStoll schrieb:

    Bei einer ausgewachsenen Klasse ist das Referenzverhalten durchaus sinnvoll, bei einer Hilfsklasse ist Kopiersemantik angebrachter.

    ich finde nicht, dass man es daran festmachen sollte.
    kopieren würde ich nur, wenn es sinnvoll ist oder sich nicht vermeiden lässt, sonst nicht.
    🙂

    Hilfsklassen sind solche, wo Kopieren sinnvoll (und mitunter notwendig) ist. Und solche kann ich in Java nicht ohne Komplikationen compilieren.

    Mal zur Anschauung ein Beispiel - ich baue mir ein Strategie-Spiel mit der Klassenhierarchie:

    class Koord//Hilfsklasse, um die Position einer Einheit zu beschreiben
    {
    private:
      int x,y;
    public:
      ...
      void Move(int dx,int dy)
      { x+=dx;y+=dy; }
    };
    
    class GameObject
    {
    private:
      Koord pos;//wo befinde ich mich?
    public:
      ...
    };
    
    class Soldier : public GameObject
    {...};
    
    class Fabric : public GameObject
    {
    private:
      Koord spos;//Startposition für erzeugte Soldaten
    public:
      Soldier* create_soldier(...)
      {
        Soldier* s = new Soldier(spos);//neue Soldaten stehen an der Startposition für die Fabrik
        return s;
      }
      ...
    };
    

    In C++ hat jeder Soldat und jede Fabrik seine eigene Position und spos wird kopiert, wenn es benötigt wird. In Java sind pos und spos nur Referenzen. Das heißt ich als Programmierer muß daran denken, eine Kopie der Position anzulegen um dann den erzeugten Soldaten damit zu initialisieren.
    (ich denke womöglich noch daran, weil das ja mein Design ist. Aber womöglich erweitert ein Kollege das Spiel um eine bewegliche Fabrik und ob der daran denkt, ist die andere Frage)



  • CStoll schrieb:

    Referenz-Zuweisung ala 'MyHelper x = y;' verbieten lassen?

    Das kannste doch in C++ auch nicht verbieten, dass einer sich nen Pointer auf ein Objekt kopiert.

    Btw, da spos ja schon zu GameObject gehört mußte es nur ein einziges mal richtig machen, nämlich im Konstruktor von GameObject. Fehler machen kann man natürlich viele. Und Du gibst Dir da scheinbar auch besondere Mühe. 🙂



  • Ja, aber ich kann verhindern, daß jemand den Pointer bekommt 😉 (zur Not, indem ich operator& entschärfe :D)



  • CStoll schrieb:

    Ja, aber ich kann verhindern, daß jemand den Pointer bekommt 😉 (zur Not, indem ich operator& entschärfe :D)

    Meinst Du das ernst?



  • Nicht wirklich (beachte das :D). Aber in meinem objigen Beispiel sind die Koord-Werte private Member. Das heißt ohne meine Erlaubnis kommt niemand an diese Objekte heran.

    (und nebenbei benötige ich die Koord-Angaben sicher noch für mehr Angaben als nur die aktuelle Position einer Einheit (dazu hätten auch zwei int-Member in der GameObject-Klasse gereicht) - einige davon in Klassen, die vom ursprünglichen Design überhaupt noch nicht vorgesehen waren)



  • Jester schrieb:

    CStoll schrieb:

    Referenz-Zuweisung ala 'MyHelper x = y;' verbieten lassen?

    Das kannste doch in C++ auch nicht verbieten, dass einer sich nen Pointer auf ein Objekt kopiert.

    und das ist eine ganz üble sache!
    (jetzt muss ich leider auch mal mit C++ vergleichen) 😉
    den pointer kann man sich in C++ lustig zurechtcasten wie man will und hebelt damit sämtliche schutzmechanismen wie 'const' und 'protected' aus.
    in Java kann man inkompatible typen oder objektreferenzen, die nicht verwand sind, nicht 'zwangscasten'.
    na, welche sprache bietet besseren schutz? 😃



  • Schutz gegen Vorsatz (und Sachen wie reinterpret_cast<> sind Vorsatz) kann wohl keine Sprache geben - Schutz gegen Fahrlässigkeit schon (dazu gehört z.B. die Möglichkeit, jemandem rein lesenden Zugriff auf meine Daten zu geben).

    PS: Und afair sind alle Klassen in Java miteinander verwandt - und wenn nur über ihren Urahnen Object.



  • CStoll schrieb:

    Schutz gegen Vorsatz (und Sachen wie reinterpret_cast<> sind Vorsatz) kann wohl keine Sprache geben....

    doch, Java :p

    CStoll schrieb:

    PS: Und afair sind alle Klassen in Java miteinander verwandt - und wenn nur über ihren Urahnen Object.

    man kann ein object zwar nach 'Object' casten, aber dann auch nur die methoden aufrufen, die 'Object' anbietet, und die sind echt harmlos.
    --> http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Object.html
    ein cast:

    Apfel a = (Apfel)eineBirne;
    

    ist nicht möglich.
    🙂



  • CStoll schrieb:
    Schutz gegen Vorsatz (und Sachen wie reinterpret_cast<> sind Vorsatz) kann wohl keine Sprache geben....
    doch, Java

    Nur setzt der Schutz auch merklich spät an. Wenn ich ein Objekt in einen inkompatiblen Typ casten will dann flieg ich zur Laufzeit auf die Schnauze.
    Zumindest mit einer akzeptablen Fehlermeldung



  • pale dog schrieb:

    CStoll schrieb:

    Schutz gegen Vorsatz (und Sachen wie reinterpret_cast<> sind Vorsatz) kann wohl keine Sprache geben....

    doch, Java :p

    OK, in Java kann man mir schlechter vorsätzlich das Design kaputtmachen (obwohl - ein Cast von Point nach MutablePoint funktioniert und hat den selben Effekt wie ein const_cast<> in C++ Code). Aber dafür ist es umso leichter, fahrlässig das Programm zu zerlegen (und erfordert Aufwand, halbwegs const-korrekte Programme zu bauen).

    CStoll schrieb:

    PS: Und afair sind alle Klassen in Java miteinander verwandt - und wenn nur über ihren Urahnen Object.

    man kann ein object zwar nach 'Object' casten, aber dann auch nur die methoden aufrufen, die 'Object' anbietet, und die sind echt harmlos.
    --> http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Object.html
    ein cast:

    Apfel a = (Apfel)eineBirne;
    

    ist nicht möglich.
    🙂

    Was heißt "nicht möglich"? Wird das schon vom Compiler geblockt oder erst zur Laufzeit?



  • templäd schrieb:

    Nur setzt der Schutz auch merklich spät an. Wenn ich ein Objekt in einen inkompatiblen Typ casten will dann flieg ich zur Laufzeit auf die Schnauze.
    Zumindest mit einer akzeptablen Fehlermeldung

    das dürfte nicht abstürzen und trotzdem seinen zweck erfüllen:

    // echt liebe klasse, von echt coolem C++ designer
    class A
    {
        private: const int a,b,c; // const und private, da kommt keiner dran  
    };
    
    // harharhar, aber ich schon !!!
    class Intruder
    {
        public: int a,b,c;
    };
    
    // mit 'const' nur so zugenagelt
    void liebe_funktion (const A*const  a)
    {
      // böser programmierer fügt code ein...
      Intruder *b = (Intruder*)a;  // hähäh !!!
      // C++ sucks, Sorry, but it does !!!
      b->a = b->b = b->c = 0x1234;  // hihihih !!!
    }
    

    CStoll schrieb:

    man kann ein object zwar nach 'Object' casten, aber dann auch nur die methoden aufrufen, die 'Object' anbietet, und die sind echt harmlos.
    --> http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Object.html
    ein cast:

    Apfel a = (Apfel)eineBirne;
    

    ist nicht möglich.
    🙂

    Was heißt "nicht möglich"? Wird das schon vom Compiler geblockt oder erst zur Laufzeit?

    es lässt sich nicht compilieren.
    🙂



  • Ja, wer böswillig sein will, geht sicher auch noch den Schritt weiter und schreibt Apfel a = (Apfel)(Object)eineBirne; (und wenn mich meine Erinnerung nicht täuscht, sollten beide Casts problemlos vom Compiler geschluckt werden). Und selbst wenn es keine Entsprechung zu reinterpret_cast<> in Java gibt, bleiben immer noch Angriffsmöglichkeiten für einen böswilligen Programmierer - aber die sind auch nicht das Thema (Stichwort: Vorsatz vs. Fahrlässigkeit).



  • Es lässt sich nicht compilieren, weil Apfel und Birne nicht in der selben Hirarchie sind. Richtig. ABER, das was wohl eher auf Java-Code zutrifft, ist ja wohl eher das, das man von Object auf einen konkreten Typ castet. Oder von einem Interface auf einen konkreten Typen. Sagen wir mal, ich habe Interface ILogIn und dazu mehrere Implementierungen. Und ich habe sowas:

    ILogIn getLogin();
    
    MyLogIn log = (MyLogIn) getLogin();
    

    Dann werde ich mit einem ClassCastException rechnen müssen.
    Noch schlimmer ist es aber, wenn sowas existiert (was in Java usos ist):

    Object get();
    

    Horror! Was haben wir hier in unseren Produktiven Systemen schon alles an ClassCastExceptions gesehen...



  • CStoll schrieb:

    Ja, wer böswillig sein will, geht sicher auch noch den Schritt weiter und schreibt Apfel a = (Apfel)(Object)eineBirne; (und wenn mich meine Erinnerung nicht täuscht, sollten beide Casts problemlos vom Compiler geschluckt werden). Und selbst wenn es keine Entsprechung zu reinterpret_cast<> in Java gibt, bleiben immer noch Angriffsmöglichkeiten für einen böswilligen Programmierer - aber die sind auch nicht das Thema (Stichwort: Vorsatz vs. Fahrlässigkeit).

    👍 😮 habs gerade in Eclipse ausprobiert, der Compiler schluckt es!



  • pale dog schrieb:

    // echt liebe klasse, von echt coolem C++ designer
    class A
    {
        private: const int a,b,c; // const und private, da kommt keiner dran  
    };
    
    // harharhar, aber ich schon !!!
    class Intruder
    {
        public: int a,b,c;
    };
    
    // mit 'const' nur so zugenagelt
    void liebe_funktion (const A*const  a)
    {
      // böser programmierer fügt code ein...
      Intruder *b = (Intruder*)a;  // hähäh !!!
      // C++ sucks, Sorry, but it does !!!
      b->a = b->b = b->c = 0x1234;  // hihihih !!!
    }
    

    💡 Das geht auch einfacher ( ⚠ aber nie so benutzen ⚠ und wenn doch, dann nicht verraten, daß ich es gesagt habe):

    #define private public
    #include <einfremderheader.h>
    

    C++ lässt halt vieles zu, aber vieles muß, bzw. kann ich explizit machen. Es gibt manchmal Spezialfälle, wo ich mich über gewisse Schutzmechanismen hinweg setzten möchte. Und das geht mit C++. Sicher macht das die Sprache nicht sicherer, aber ich werde von der Sprache auch nicht in den Möglichkeiten eingeschränkt. Mit C++ lässt sich einfach (fast) alles machen, was der Rechner her gibt.



  • Artchi schrieb:

    CStoll schrieb:

    Ja, wer böswillig sein will, geht sicher auch noch den Schritt weiter und schreibt Apfel a = (Apfel)(Object)eineBirne; (und wenn mich meine Erinnerung nicht täuscht, sollten beide Casts problemlos vom Compiler geschluckt werden). Und selbst wenn es keine Entsprechung zu reinterpret_cast<> in Java gibt, bleiben immer noch Angriffsmöglichkeiten für einen böswilligen Programmierer - aber die sind auch nicht das Thema (Stichwort: Vorsatz vs. Fahrlässigkeit).

    👍 😮 habs gerade in Eclipse ausprobiert, der Compiler schluckt es!

    klar, mit dem doppelcast nimmste dem compiler die möglichkeit sich zu beschweren, aber versuch mal, deine so trickreich gecastete referenz zu benutzen...
    bereits die zeile nach dem cast wird schon nicht mehr ausgeführt.
    wäre es ein C++ programm (siehe mein beispiel oben), dann ginge es trotzdem. 😃

    tntnet schrieb:

    💡 Das geht auch einfacher ( ⚠ aber nie so benutzen ⚠ und wenn doch, dann nicht verraten, daß ich es gesagt habe):

    #define private public
    #include <einfremderheader.h>
    

    nicht jeder compiler lässt keywords in defines zu 😉

    tntnet schrieb:

    Es gibt manchmal Spezialfälle, wo ich mich über gewisse Schutzmechanismen hinweg setzten möchte. Und das geht mit C++.

    wie war das doch mit 'aus der not eine tugend machen' 😉
    eine programmiersprache, die es erlaubt die eigenen schutzmechanismen zu umgehen, hat im endeffekt gar keine schutzmechnismen
    🙂



  • pale dog schrieb:

    klar, mit dem doppelcast nimmste dem compiler die möglichkeit sich zu beschweren, aber versuch mal, deine so trickreich gecastete referenz zu benutzen...
    bereits die zeile nach dem cast wird schon nicht mehr ausgeführt.
    wäre es ein C++ programm (siehe mein beispiel oben), dann ginge es trotzdem.

    Nö, ich habs ausprobiert. Der Compiler kompiliert die nachfolgende Zeile ohne Probleme.

    Birne birne = new Birne();
    Apfel apfel = (Apfel) (Object) birne;
    apfel.toString();
    


  • Artchi schrieb:

    Nö, ich habs ausprobiert. Der Compiler kompiliert die nachfolgende Zeile ohne Probleme.

    Er kompiliert, wird sich aber mit ner Exception beschweren wenn du den faulen Apfel benutzen willst.



  • pale dog schrieb:

    Artchi schrieb:

    CStoll schrieb:

    Ja, wer böswillig sein will, geht sicher auch noch den Schritt weiter und schreibt Apfel a = (Apfel)(Object)eineBirne; (und wenn mich meine Erinnerung nicht täuscht, sollten beide Casts problemlos vom Compiler geschluckt werden). Und selbst wenn es keine Entsprechung zu reinterpret_cast<> in Java gibt, bleiben immer noch Angriffsmöglichkeiten für einen böswilligen Programmierer - aber die sind auch nicht das Thema (Stichwort: Vorsatz vs. Fahrlässigkeit).

    👍 😮 habs gerade in Eclipse ausprobiert, der Compiler schluckt es!

    klar, mit dem doppelcast nimmste dem compiler die möglichkeit sich zu beschweren, aber versuch mal, deine so trickreich gecastete referenz zu benutzen...

    Mit deinem ekligen C-Style Cast hast du auch nicht viel anderes gemacht, als den Compiler ruhigzustellen.

    tntnet schrieb:

    Es gibt manchmal Spezialfälle, wo ich mich über gewisse Schutzmechanismen hinweg setzten möchte. Und das geht mit C++.

    wie war das doch mit 'aus der not eine tugend machen' 😉
    eine programmiersprache, die es erlaubt die eigenen schutzmechanismen zu umgehen, hat im endeffekt gar keine schutzmechnismen
    🙂

    Da sind wir wieder beim Konflikt "Vorsatz vs. Fahrlässigkeit" - wer vorsätzlich handelt, kann so ziemlich jeden Schutzmechanismus der Sprache aushebeln (ich bin sicher, es gibt auch Mittel und Wege, um unter Java die privaten Member einer fremden Klasse zu manipulieren). Fahrlässigkeit betrifft dagegen Leichtsinnsfehler - und gegen sowas sollte einen der Compiler eigentlich schützen (ein Beispiel für einen solchen Schutz ist die Const-Correctness - wenn ich es sage, sollte ein Kollege auf direktem Weg auch nichts an meinen Objekten ändern dürfen).


Anmelden zum Antworten