const in Java und interface's ...



  • besserwißer schrieb:

    falsch, das ganze beispiel ist nämlich blödsinn. woher und wieso sollte die garage überhaupt die farben ihrer autos kennen und speichern? wenn dann gäb es eine methode garage.findeAuto("mercedes") und eine methode auto.getFarbe() und/oder auto.setFarbe(Farbe). mal mir mal bitte zu deinem beispiel ein vernünftiges uml klassendiagramm *lol*

    Und du willst wirklich erlauben, daß die Garage das gefundene Auto nebenbei zum Mond schießen darf? 😉



  • Auf gleiche Weise könnten sich Java Programmierer fragen warum es kein final in C++ gibt (für Klassen und Methoden).

    Mit final löst man die Probleme in Java die ein C++ Programmierer mit const löst. final und const sind zwar grundverschieden (abgesehen von primitiven Datentypen) aber Lösen die gleichen Probleme. Allerdings ist die Herangehensweise eine völlig andere.

    Das gleiche Thema haben wir z.B. auch bei Interfaces vs. Multiple Vererbung.

    In meinen Augen fehlt weder Java ein const noch C++ ein final. Auch sind beide in ihrer jeweiligen Sprache völlig berechtigt und auch nötig. Es ist einfach eine andere Art des Designs. In beiden Welten sind die Benutzer irgendeiner Klasse völlig aufgeschmissen wenn sich der Klassendesigner nicht an die üblichen Konventionen gehalten hat. Weder const, final noch irgend eine andere Spracheigenschaft könnte dann noch wirklich helfen.

    MfG,
    Hilefoks



  • Hilefoks schrieb:

    Mit final löst man die Probleme in Java die ein C++ Programmierer mit const löst. final und const sind zwar grundverschieden (abgesehen von primitiven Datentypen) aber Lösen die gleichen Probleme. Allerdings ist die Herangehensweise eine völlig andere.

    Nein. Final und const lösen komplett andere probleme 😉

    Aber niemand hier sagt, dass const in java fehlt. Ich habe mehrfach gesagt dass die Probleme die const löst in java anders gehandhabt werden: immutable objekte bzw. defensive kopien.

    final wird in c++ anders gemacht: durch das fehlen von virtual hat man etwas das sich ähnlich wie final verhält.

    eine klasse ohne virtuellen dtor ist praktisch final. eine nicht virtuelle funktion ist praktisch final.



  • soll das heißen du versuchst in einer anderen klasse (Garage) den internen zustand einens objekts zu verwalten? sorry das ist blödsinn und kein vernünftiges objektorientiertes design. entweder du bringst ein nervünftiges real world beispiel oder ich brauch hier nicht mehr zu lesen 👎



  • asdasd schrieb:

    soll das heißen du versuchst in einer anderen klasse (Garage) den internen zustand einens objekts zu verwalten? sorry das ist blödsinn und kein vernünftiges objektorientiertes design. entweder du bringst ein nervünftiges real world beispiel oder ich brauch hier nicht mehr zu lesen 👎

    Die Farbe ist doch kein interner Zustand 😕

    Aber die Beispiele sind in der Tat nicht geeignet, da const nicht mehr als ein Hilfsmittel für den Programmierer ist. Ein const hat keine Auswirkungen in einem fehlerfreien Programm. Aber um genau das zu erreichen, ein fehlerfreies Programm, bietet es sich an mit const die Möglichkeiten einzuschränken um (ungewollte) Seiteneffekte zu vermeiden. Es ist übrigens möglich innerhalb von einer const-Methode Attribute zu verändern die mit dem Schlüsselwort mutable versehen wurden. Dadurch ist es möglich den internen Zustand eines Objekts zu verändern, aber gleichzeitig kann die Garantie gegeben werden, dass der externe Zustand erhalten bleibt (unter der Annahme, dass bei der Implementierung keine Seiteneffekte auftreten in Verbindung mit den mutable Attributen).

    Wenn du sagst man braucht const nicht, dann hast du recht, aber es ist ein Hilfsmittel um Bugs zu vermeiden.



  • asdasd schrieb:

    soll das heißen du versuchst in einer anderen klasse (Garage) den internen zustand einens objekts zu verwalten? sorry das ist blödsinn und kein vernünftiges objektorientiertes design. entweder du bringst ein nervünftiges real world beispiel oder ich brauch hier nicht mehr zu lesen 👎

    Nein, die Garage verwaltet ihren eigenen Zustand (eine Sammlung von Autos). Mit geeignet gesetzten const's kann ich verhindern, daß sie dabei den internen Zustand dieser Autos beeinflussen kann. (Wenn ich selber die Garage entwickle, weiß ich, was sie tun darf. Aber ein Kollege sieht nur die Methoden der Auto-Klasse und könnte auf die Idee kommen, sie auch zu nutzen.)



  • CStoll schrieb:

    Nein, die Garage verwaltet ihren eigenen Zustand (eine Sammlung von Autos). Mit geeignet gesetzten const's kann ich verhindern, daß sie dabei den internen Zustand dieser Autos beeinflussen kann. (Wenn ich selber die Garage entwickle, weiß ich, was sie tun darf. Aber ein Kollege sieht nur die Methoden der Auto-Klasse und könnte auf die Idee kommen, sie auch zu nutzen.)

    Sorry, wenn Eure Auto so geschnitten sind, dass sie eine Änderung der Farbe zulassen, dann seid Ihr selbst schuld. Wenn ich die Möglichkeiten zur Verfügung stelle, dann muss ich mich nicht wundern, wenn sie benutzt werden.

    Ausserdem ist es schon komisch, einer 'blauen' Instanz des Objekts 'Farbe' per Accessor in einen anderen Zustand versetzen zu können und sich dann zu ärgern, dass jemand von außen das auch kann.
    Warum dann nicht so:
    Objekt 'Autolack' mit final Attribut 'Farbe'. getFarbe beim Auto könnte diesen Antworten oder aber nur auf getAutolack reagieren.
    Wenn ein Auto jetzt die Farbe ändern will oder das von außen zulassen will, dann muß eine neue Instanz von 'Autolack' mit Attribut bsw. 'rot' erzeugt und gesetzt werden oder nur rot und der Rest passiert intern.
    Statt 'Autolack' geht auch einfach ein String-Konstante (weil String per 'call-by-value' benutzt werden).

    Die Frage ist nur, bietet Auto ein setFarbe an, oder nicht. Wer die aufrufen kann, kann per protected/package/public gelöst werden.

    Es stimmt aber, dass ich jetzt nicht die Klasse 'Lackierer' als 'Friend' definieren kann, weil das in Java nicht gibt.
    Auch wenn's nicht das selbe ist, dann könnte man ein Interface ILackierer definieren. Wenn Garage dieses nun implementiert und damit 'fähig' ist, denn Lack zu ändern dann ist das auch OK.

    Man sollte bei der Diskussion auch nicht vergessen, dass ich Kollegen (oder wen auch immer) niemals daran hindern kann, Böses mit dem eigenen Code zu machen. Will sagen:
    Wenn mein lieber Kollege R. ein Objekt 'Autobahn' schreibt, das ILackierer implementiert, dann ist der Fehler im System, dass der damit durchkommt und nicht, dass Java nicht die Möglichkeit bietet das zu vermeiden.
    Wenn ich in C++ Böses machen will, dann kann ich dort auch auf den Speicherbereichen rumarbeiten.

    Das Design ist halt einfach etwas anders und (entschuldigt bitte) ich habe manchmal das Gefühl, dass langjährige C-Entwickler (und C++ fällt in diesem Fall unter C) zur Problemlösung zu selten die Möglichkeiten der Objektorientierung nutzen, egal in welcher Sprache (aber kein Vorwurf!).

    Vielleicht hilft ein andere Denkansatz ja, wollte niemanden beleidigen und total verwirren - ist halt doch ein Roman geworden.



  • Ja, Schutz gegen Böswilligkeit kann keine Sprache bieten (sie kann entsprechende Versuche nur erschweren), Schutz gegen Fahrlässigkeit dagegen schon.

    (und inzwischen habe ich auch eingesehen, daß sich die Sichtweisen von C++ und Java teilweise zu stark unterscheiden - vermutlich ist da ein Grund, warum Anhänger beider Sprachen so oft aneinandergeraten)

    OK, werden wir etwas abstrakter: Objektorientierung lebt ja auch von der Interaktion zwischen den Objekten - das läuft dann meistens darauf hinaus, daß ein Objekt an eine Methode des anderen Objekts übergeben wird. Zum Beispiel kann man die Ausgabe lösen als 'printer.print(mein_objekt);' oder als 'mein_objekt.printto(printer);' (aus const-correctness Sicht wäre wohl letzteres angebracht, weil meine Methoden in meiner eigenen Verantwortung liegen). Aber wie sieht es aus, wenn mehr als zwei Objekte an der Interaktion beteiligt sind? (z.B. bekommt ein LGS-Löser eine Matrix M und einen Vektor b und sollte keinen von beiden verändern dürfen)



  • CStoll schrieb:

    Ja, Schutz gegen Böswilligkeit kann keine Sprache bieten (sie kann entsprechende Versuche nur erschweren), Schutz gegen Fahrlässigkeit dagegen schon.

    Da gebe ich Dir recht, allerdings behaupte ich, dass sich Java da von Haus aus wesentlich besser anbietet... Pointer, Speicherzugriffe, durchgängiges Exceptionhandling, wesentlich einheitlichere API. Wie eigentlich immer, wenn etwas neu ist.

    CStoll schrieb:

    ... lösen als 'printer.print(mein_objekt);' oder als 'mein_objekt.printto(printer);' (aus const-correctness Sicht wäre wohl letzteres angebracht, weil meine Methoden in meiner eigenen Verantwortung liegen)....

    Auch hier stimme ich nicht automatisch zu: Für mich ist das eher eine Frage der Fachlichkeit und vor allem der technische Möglichkeiten, ob jedes meiner Objekte selbst weiß, wie es gedruckt wird, oder ob eine 'Drucker' sich damit auskennt und alle anderen Drucken kann.
    Gerade bei dem Beispiel ist aber vermutlich sowieso eine Zwischenschicht (XML-Doks o.ä.) sinnvoll, weil zum Druck oft doch alle Daten bekannt sein müssen, die aber im Objektnetz nicht öffentlich sein sollen. Das wäre dann das Mittelding: Jeder legt fest, was gedruckt werden darf/soll/muss und überläßt das wann/wie/womit/... einem andern Objekt (Für den Datenaustausch bietet sich dann übrigens ein Interface und keine konkrete Klasse an).
    Oder man benutzt toString :-))

    Außerdem liegen 'meine Methoden' doch in meiner Verantwortung, die Frage ist doch, wie designe ich meine Methoden und meine Daten. Wenn alles zum Drucken über Getter erreichbar ist, dann kann da doch niemand herummanipulieren.
    Davon abgesehen kann ein Drucksystem auch mal ausgetauscht werden oder erweitert, z.B. neben Papierdruck auch Erzeugung von HTML. Dann ist es besser, wenn alle Objekte in einem Format liefern die die eigentliche technische Umstellung/Erweiterung nur im Druck-System stattfindet.



  • SammyRukka schrieb:

    Außerdem liegen 'meine Methoden' doch in meiner Verantwortung, die Frage ist doch, wie designe ich meine Methoden und meine Daten. Wenn alles zum Drucken über Getter erreichbar ist, dann kann da doch niemand herummanipulieren.

    Siehst du und das ist das Problem - der Drucker darf nur über die Getter zugreifen, aber andere Klassen (z.B. meine Prozesssteuerung) darf auch die Setter-Methoden verwenden. Und da fehlt imho eine Möglichkeit, konsequent zu trennen, wer was machen darf.

    Die C++ Umsetzung:

    class test
    {
      ...
    public:
      int get_data() const;
      void set_data(int);
    };
    
    class printer
    {
    public:
      virtual void print_test(const test&)=0;//darf nur den Getter nutzen
      virutal void print_testlist(const vector<test>&)=0;//darf auch nur die Getter der Elemente nutzen
    };
    
    class manager
    {
    public:
      virtual void update(test&)=0;//hat vollen Zugriff auf alle public-Methoden
    };
    
    int main()
    {
      vector<test> my_data;
      printer* the_printer = get_system_printer();
      ...
      printer->print_testlist(my_data);
    }
    

    Und der Versuch in Java:

    interface const_test
    {
    public int get_data();
    };
    
    class test implements const_test
    {
      ...
    public int get_data(){..}
    public void set_data(int v){..}
    };
    
    interface printer
    {
    public void print_test(const_test);//kann nur die getter nutzen, die const_test deklariert hat
    public void print_testlist(const_vector<test>);//kann theoretisch alle Methoden von test nutzen
    };
    
    interface manager
    {
    public void update(test);
    };
    
    class programm
    {
    public static void Main(...)
    {
      vector<test> my_data = new vector<test>;
      printer = get_system_printer();
      ...
      printer.print_testlist(my_data);
    

    Das Hauptproblem dabei ist, daß ich entweder meinen kompletten vector kopieren müsste in einen vector<const_test> oder zulasse, daß printer.print_testlist() die Chance hat, meine Objekte zu manipulieren. (und was sich wirklich hinter dem printer verbirgt, liegt nicht mehr in meiner Hand - ich habe nur die öffentliche Schnittstelle)

    (das zweite Problem von oben - test.get_data() könnte den Status ändern - ist nicht ganz so kritisch, weil die Methode in meinen Zuständigkeitsbereich fällt)



  • Klar, wie gesagt, 'friend' gibt's nicht, höchsten die Modifier package, protected...

    Widersprechen kann ich Dir da auch nicht. Kann nur sagen, daß ich 5 Jahre lange an einer recht großen, vielseitigen und -schichtigen Business-Anwendung entwickelt habe und sich die Probleme in der Praxis nicht gestellt haben. Die Anwendung ist in Subsysteme geteilt mit klaren Schnittstellen (hier Interfaces), an die sich beide Seiten halten mußten. Und da ging man normalerweise auch nicht im fremden Revier wildern.... und sonst könnte man dabei auch die eigentlich geschützte C++-Klasse direkt ändern.... Naja, entweder habe ich einen fachlich Grund etwas zu ändern, dann muß ich es dürfen, oder ich 'kann es eigentlich nicht', habe aber trotzdem die technische Möglichkeit.

    public void print_test(const_test);//kann nur die getter nutzen, die const_test deklariert hat
    public void print_testlist(const_vector<test>);//kann theoretisch alle Methoden von test nutzen

    Nee, wieso? Das zweite ist falsch (oder ich verstehe Dich falsch)
    Das Interface kann ersteinmal gar nichts. Und dann ist es egal, ob Du eine Instanz von const_test übergibst oder mehrere in einem Vector. Entscheidend ist die Schnittstelle von const_test. Und genau hier könntest Du ein Interface 'IConstTestDruckApi' (oder wie auch immer definieren), das wiederum nur die Getter implementiert also sieht das dann so aus:

    public void print_test(IConstTestDruckApi meinObjekt);
    

    ...Ja, auch richtig, das kann ich dann wieder auf die konkrete Klasse casten, aber die Umwege kann man in C++ auch gehen und wenn das jemand deshalb macht...

    Für mich:
    Was enthält Dein Vector >>const vector<test>&<< in C++ denn, Funktionspointer oder Pointer auf die Attribute?

    Wie wär's denn sonst mit einem Vector von Paaren Attributname/Value oder einer XML als Austauschformat, da kann auch nichts geändert werden.

    Es gibt also auch technisch genügen Möglichkeiten in Java zu Außenschnitttellen ordentlich zu beschreiben. Mit 'Hacker'-Kollegen hat man sowieso Probleme, egal welche Sprache 😉

    ---

    Die Frage ist doch eigentlich auch, wie umfangreich der Druck sein soll. Davon hängt doch auch die Implementierung in C++ ab:
    Wenig: Call-by-Value (string in C++ oder String in Java) oder Natives oder wird sie komplexer, dann ist man ganz schnell dabei, daß man sich eine Zwischenschicht ausdenkt.
    Wenn ich das 'Information-Hiding' der OO anführe, dann reicht ein const auch nicht, denn lesen kann ich immernoch alles und ist es nicht auch so, daß ich in C die viel gepriesene Möglichkeit habe, über die Adresse eines Attributs doch den Inhalt zu schreiben oder zu verdrehen ?!

    ---

    Ach ja, Quasi-Call-by-value erreichst Du ja auch durch ein clone(), dann kann geändert werden was will, die Kopie-Instanz ist ja nicht das Original....



  • CStoll schrieb:

    public void print_testlist(const_vector<test>);//kann theoretisch alle Methoden von test nutzen
    

    es muss ja auch

    public void print_testlist(const_vector<const_test>);
    

    heissen 😉



  • SammyRukka schrieb:

    Klar, wie gesagt, 'friend' gibt's nicht, höchsten die Modifier package, protected...

    Widersprechen kann ich Dir da auch nicht. Kann nur sagen, daß ich 5 Jahre lange an einer recht großen, vielseitigen und -schichtigen Business-Anwendung entwickelt habe und sich die Probleme in der Praxis nicht gestellt haben. Die Anwendung ist in Subsysteme geteilt mit klaren Schnittstellen (hier Interfaces), an die sich beide Seiten halten mußten. Und da ging man normalerweise auch nicht im fremden Revier wildern.... und sonst könnte man dabei auch die eigentlich geschützte C++-Klasse direkt ändern.... Naja, entweder habe ich einen fachlich Grund etwas zu ändern, dann muß ich es dürfen, oder ich 'kann es eigentlich nicht', habe aber trotzdem die technische Möglichkeit.

    public void print_test(const_test);//kann nur die getter nutzen, die const_test deklariert hat
    public void print_testlist(const_vector<test>);//kann theoretisch alle Methoden von test nutzen

    Nee, wieso? Das zweite ist falsch (oder ich verstehe Dich falsch)
    Das Interface kann ersteinmal gar nichts. Und dann ist es egal, ob Du eine Instanz von const_test übergibst oder mehrere in einem Vector. Entscheidend ist die Schnittstelle von const_test. Und genau hier könntest Du ein Interface 'IConstTestDruckApi' (oder wie auch immer definieren), das wiederum nur die Getter implementiert also sieht das dann so aus:

    public void print_test(IConstTestDruckApi meinObjekt);
    

    Wie ich das Interface nenne, ist erstmal egal - const_test in obigem Beispiel enthält alle nötigen Getter, die der Drucker benötigt.

    Für mich:
    Was enthält Dein Vector >>const vector<test>&<< in C++ denn, Funktionspointer oder Pointer auf die Attribute?

    Der vector enthält Objekte (vom Typ test) - und ein 'const vector<>&' ist eine Referenz auf so einen vector (mit der Zusicherung, daß er selbst und alle seine Elemente konstant sind).

    Wie wär's denn sonst mit einem Vector von Paaren Attributname/Value oder einer XML als Austauschformat, da kann auch nichts geändert werden.

    Ja, das läuft wieder darauf hinaus, daß irgendwer alle Objekte des vector<>s kopieren/aufbereiten/... muß, bevor sie an den Drucker übergeben werden können.

    Ach ja, Quasi-Call-by-value erreichst Du ja auch durch ein clone(), dann kann geändert werden was will, die Kopie-Instanz ist ja nicht das Original....

    Ja, sicher - aber damit kommen wir in die Bereiche, wo die Laufzeit eine Rolle spielt (und der Grund, warum man in C++ const-Referenzen hat - ich habe cbv-Semantik, ohne mich mit den Kosten einer Kopie rumschlagen zu müssen).

    Undertaker schrieb:

    CStoll schrieb:

    public void print_testlist(const_vector<test>);//kann theoretisch alle Methoden von test nutzen
    

    es muss ja auch

    public void print_testlist(const_vector<const_test>);
    

    heissen 😉

    Und Java erlaubt es wirklich, an DIESE Funktion meinen 'vector<test> my_data' zu übergeben?



  • Undertaker schrieb:

    CStoll schrieb:

    public void print_testlist(const_vector<test>);//kann theoretisch alle Methoden von test nutzen
    

    es muss ja auch

    public void print_testlist(const_vector<const_test>);
    

    heissen 😉

    Und Java erlaubt es wirklich, an DIESE Funktion meinen 'vector<test> my_data' zu übergeben?[/quote]

    Ja, solange die Klasse test das Interface const_test implementiert hat. Bei dir ist das ja der Fall 😉

    PS: Abseits der Diskussion, es ist erstaunlich, wie sehr man sich an die sun coding conventions (insb. Namensgebung/Schreibung) gewöhnt und dann andere Bennenung kaum noch lesen kann.
    Klassen und Interfaces: groß,
    normalerweise keine Unterstriche sondern mit Großbuchstaben trennen



  • Also eine der ersten Grundlagen in OOP, die ich gelernt habe, ist daß ein Container einer abgeleiteten Klasse kein Container der Basisklasse ist (sonst könnte man ja auch einen vector<Auto> als vector<Fahrzeug> übergeben und bekommt plötzlich Boote dort reingepackt). Und da const kein Java Sprachkonzept ist, dürfte es für den Compiler keinen Unterschied zwischen der Umwandlung vector<Auto> -> vector<Fahrzeug> und vector<test> -> vector<const_test> geben, oder?

    PS: @Namen: alles eine Sache der Gewöhnung - in C++ hat sich nunmal komplette Kleinschreibung mit Unterstrichen durchgesetzt 😉



  • Schreibstil:
    Geht mir genauso. Auch nach Monaten C++ ist das alles immernoch häßlich für mich. Dazu kommt auch noch die Formatierung an sich. Unter Java/Eclipse hatten wir einen Formatter der beim Speichern darüber ging, so sah das alles sehr ähnlich aus.
    Jetzt muß ich mir C++-Code von Generationen von Entwicklern ansehen, die alle so platzraubend und komisch formatieren (und das ist nur die Formatierung)... 🙂

    Du kannst in Java in den Vector jedes 'Object' reinschmeissen. Ob das guter Stil ist, kommt auf die Situation an.
    Für mich ist es OK, wenn der Vector 'meineFahrzeuge' heißt und Instanzen von 'PKW', 'Motorrad' und 'Tretroller' enthält, wobei alle am besten von 'Fahrzeug' erben sollten.
    Je nach Kontext sind vielleicht sogar 'Boot' und 'Drachenflieger' OK.
    In anderen Situationen sollten vielleicht sogar ausschließlich 'PKW' drin sein, durch die Sprache wirst Du da aber nicht festgelegt, außer Du nimmst ein Array von 'KFZ', was ich aber nur selten mache, weil ein Vector viel flexibler ist.



  • SammyRukka schrieb:

    Du kannst in Java in den Vector jedes 'Object' reinschmeissen. Ob das guter Stil ist, kommt auf die Situation an.
    Für mich ist es OK, wenn der Vector 'meineFahrzeuge' heißt und Instanzen von 'PKW', 'Motorrad' und 'Tretroller' enthält, wobei alle am besten von 'Fahrzeug' erben sollten.

    Wenn ich auf globaler Ebene einen vector<const_test> hätte, wäre es ja vorstellbar, dort test's reinzuwerfen. Aber umgekehrt in einen vector<test> ein const_test (das eventuell nur gar nicht die set-Methoden definiert hat, die ich im Hauptprogramm benötige) zu packen, ist eine andere Sache.

    PS: Wenn der Vector wirklich nur 'Object'e ohne irgendeine Typkontrolle enthält, ist's sogar noch schlimmer - da wird der Nutzer ja gezwungen zu casten, um die Objekte sinnvoll verwenden zu können.



  • Naja, sauber zu arbeiten lohnt sich halt immer.
    Auch hier habe ich eigentlich niemals das Problem gehabt, das ich nicht gewußt hätte, was ankommt. Im Gegenteil, manchmal braucht man soetwas ja auch (oder meint das zumindest). Das sind die Fälle, bei denen man in C++ dann Void-Pointer benutzt, da finde ich die Java-Lösung besser.
    Das wiederspricht ja auch nicht der OO. Wenn Du da sicher sein willst, dann kannst Du ja auch eine 'KfzListe' implementieren, die die eigentliche Liste und die speziellen Funktionen kapselt.
    Ach ja, toString() können sie in Java alle, da brauchst Du keinen Cast! 🙂

    Und zu dem global habe ich so eine andere Meinung. Das ist wie static-Attribute etwas, auf das in 90% der Fälle Höchststrafe stehen sollte.

    Außerdem finde ich schon, daß Java typsicher ist. Wenn Du anderer Meinung bist, dann hast Du noch niemals in Smalltalk programmiert - und das ist immerhin die objektorientierte Sprache schlechthin!

    ---

    Aber letztendlich wird das alles sehr offtopic (auch wenn ich ganz interessant finde). Letztlich bleibt zu sagen, daß es für const in Java keinen direkten Pendant gibt, aber halt auch nicht geben muß.
    Wenn alles in C++ und Java gleich laufen würde und man nur die Vokabeln getauscht hätte, dann hätte man sich das auch sparen können.
    In der Gesamtheit läßt sich aber auch alles lösen, nur halt auf andere Art - genauso paßt dazu das Thema 'multiple Vererbung': Die einen sagen 'braucht Java nicht', die anderen 'kann Java' nicht. Beides ist wahr.



  • SammyRukka schrieb:

    Sorry, wenn Eure Auto so geschnitten sind, dass sie eine Änderung der Farbe zulassen, dann seid Ihr selbst schuld. Wenn ich die Möglichkeiten zur Verfügung stelle, dann muss ich mich nicht wundern, wenn sie benutzt werden.

    Das ist der Punkt.

    mit const garantierst du, dass getFoo nur ein Foo returned ohne das Objekt selber zu ändern. Es ist einfach eine Garantie die das Objekt gibt.

    Ausserdem ist es schon komisch, einer 'blauen' Instanz des Objekts 'Farbe' per Accessor in einen anderen Zustand versetzen zu können und sich dann zu ärgern, dass jemand von außen das auch kann.
    Warum dann nicht so:
    Objekt 'Autolack' mit final Attribut 'Farbe'. getFarbe beim Auto könnte diesen Antworten oder aber nur auf getAutolack reagieren.

    final bringt dir nichts, ich kann dennoch getFarbe().aendere() aufrufen. Das einzige was funktioniert ist Farbe als immutable zu haben.

    Und im Prinzip ist const genau das: du machst aus einem mutable Objekt mit dem qualifier const einfach ein immutable Objekt.

    Kleines Beispiel:
    Farbe kann immutable sein, aber was wenn man ein Komplexes Objekt hat? zB getMotor().
    Wenn Motor nun Operationen hat die den Motor verändern. Beispiel: reparieren().
    Wie erlauben wir einem Client einen View auf den Motor ohne dass er rumpfuschen darf? Motor kann nicht immutable sein. In Java würde man jetzt eine defensive Kopie machen. Funktioniert auch problemlos. Meistens hat man ja immutable Objekte und wenn mal nicht, dann halt ne defensive Kopie. Tut nicht wirklich weh. Oder man verlässt sich einfach auf den Client Code - auch sehr legitim.

    In C++ hat man diese Gedankengänge aber nicht: man liefert einfach einen immutable Motor. Damit kann Auto vom Client Code verlangen: du darfst den Motor ansehen, aber nicht anfassen.

    Diese Anforderung kann man natürlich auch in die Doku schreiben und das Programm wird nicht kaputt gehen dadurch. Es ist einfach eine Hilfe um gewissen Fehlern vorzubeugen.

    PS:
    Wenn dich schon die Formatierungen stören... Dann bist du wohl sehr penibel. Die wirklichen Unterschiede offenbaren sich erst ein paar Levels tiefer 😉

    zB alleine das Klassendesign ist komplett unterschiedlich...

    @CStoll:
    Java hat keine Templates, ergo wird alles über laufzeit polymorphie gelöst. Generics sind eine automatisierte Variante zum einfügen von den Casts an den richtigen Stellen. Im Prinzip hat man in Java also immer nur vector<Object>



  • SammyRukka schrieb:

    Naja, sauber zu arbeiten lohnt sich halt immer.
    Auch hier habe ich eigentlich niemals das Problem gehabt, das ich nicht gewußt hätte, was ankommt. Im Gegenteil, manchmal braucht man soetwas ja auch (oder meint das zumindest). Das sind die Fälle, bei denen man in C++ dann Void-Pointer benutzt, da finde ich die Java-Lösung besser.

    einen void-Zeiger oder ein allgemeines Object zu verwenden nimmt sich im Endeffekt nicht sehr viel - in beiden Fällen mußt du casten, um etwas sinnvolles mit dem Objekt zu machen (ja, Java reagiert da etwas deutlicher, wenn du falsch castest.

    Das wiederspricht ja auch nicht der OO. Wenn Du da sicher sein willst, dann kannst Du ja auch eine 'KfzListe' implementieren, die die eigentliche Liste und die speziellen Funktionen kapselt.

    Wozu gibt es denn in Java Generics, wenn sie dann doch wieder alles auf 'Object'-Referenzen herunterbrechen? Wenn ich einen vector<KFZ> habe, sollen da nur KFZ's reinkommen und keine Motorboote - indem du erlaubst, diesen als vector<Fahrzeug> oder vector<Object> zu betrachten, unterläufst du die Grundbedingungen (und hast plötzlich doch ein Boot oder gar einen String in dem Vector stehen, der dort nichts zu suchen hat).

    Ach ja, toString() können sie in Java alle, da brauchst Du keinen Cast! 🙂

    Aber toString() ist auch keine eierlegende Wollmilchsau 😉

    Und zu dem global habe ich so eine andere Meinung. Das ist wie static-Attribute etwas, auf das in 90% der Fälle Höchststrafe stehen sollte.

    OK, vielleicht war 'global' die falsche Bezeichnung - ich meinte damit den vector<> in der Main(), der bei Bedarf herumgereicht werden kann.

    Aber letztendlich wird das alles sehr offtopic (auch wenn ich ganz interessant finde). Letztlich bleibt zu sagen, daß es für const in Java keinen direkten Pendant gibt, aber halt auch nicht geben muß.

    OK, das sehe ich ein - auch wenn ich die Gründe dahinter immer noch nicht richtig verstehe (bei mir zieht sich const-correctness normalerweise quer durch alle Programmteile).


Anmelden zum Antworten