Vererbungsfrage
-
Hallo zusammen,
vielen Dank für die doch überraschende aber klare Aussage.
Schade, ich habe gedacht, dass das zum OO gehört, und dass das auch in C++ so realisierbar ist. Aber dass das nicht geht habe ich verstanden.
Vielen Dank.
Gruß
Norman-Timo
-
Nunja, man kann den Effekt in C++ schon erreichen, zB indem man PolyMethod in Kind_B einen default Parameter einer non-public nested Klasse mit gibt und dadurch eine andere Signatur erzwingt. Der Client wird bei der Verwendung keinen Unterschied merken Höchstens bei einem angegebenen Parameter beim Funktionsaufruf über eine andere Fehlermeldung überrascht sein. Ein andere Möglichkeit wäre evtl. auch statische Vererbung mittels Templates. Dennoch erschliesst sich mir nicht der Sinn des Ganzen. Ich denke, in C++ dürften sinnvolle Anwendungen davon relativ begrenzt sein. Die Philosophie ist nunmal eine etwas andere. virtual (override) wirkt _immer_ primär und ein downgrade ist nicht vorgesehen.
-
Hallo groovemaster,
da ich von der C# Welt komme, kenne ich dort zumindest das konkrete Beispiel die Methode ToString(), die JEDEM Objekt vererbt wird.
So ist das Problem, wenn ich diese Methode irgendwo fest überschreiben würde, dann wäre bei einem Cast auf ein hierarchisch höher liegenenden Typ die Eigenschaft verdreht, die die Methode eigentlich liefern sollte.
Also z.B. wenn ich bei einem UrUrUrVater die Methode aufrufe, könnte das eine andere Wirkung zeigen, wie wenn ich das von dem KindKindKind Objekt tun würde. Ein "Backcast" auf den UrUrUrVater sollte hier auch die ursprüngliche Methode liefern, weil sie z.B. in dessen Kontext sinnvoller ist.
Ich denke das ist schon recht "brauchbar", auch wenn bisher darauf verzichtet werden musste.
Nichtsdestotrotz, wenn ich mit einem Pfeil durch die Brust ins Auge schießen muss, nur um diesen Effekt in C++ zu erreichen, dann überlege ich mir lieber einen anderen Designansatz

Gruß
Norman-Timo
-
Hallo zusammen,
kann ich in C++ nicht immer auf eine Methode der Basisklasse zurückgreifen, in dem ich sie explizit aufrufe? Unter VS funktioniert es folgendermaßen:
Basisklasse:
class Basis { public: // Konstruktor Basis(void) { } // Methode zum Überladen virtual string PolyMethod(void) { return "Hallo von der Basis!"; } };Abgeleitete Klasse:
class Kind_A : public Basis { public: // Konstruktor Kind_A(void) { } // Überladene Methode string PolyMethod(void) { return "Hallo von Kind_A!"; } };Main:
int main(void) { // lokale Variablen Kind_A meinKindA; // Ausgabe der redefinierten Methode cout << meinKindA.PolyMethod() << endl; // Ausgabe der Basismethode cout << meinKindA.Basis::PolyMethod() << endl; return 0; }erzeugt bei mir die Ausgabe:
Hallo von Kind_A! Hallo von der Basis!
-
ja
-
joomoo schrieb:
ja
Hm, soll das heißend, dass das standardkonform ist? Irgendwie bricht das mit dem Konzept von Vererbung finde ich... und kann ich das dann nur durch private/protected ableiten verhindern?
-
Mir ist leider nicht bekannt, ob es sich hierbei um standard-konformes C++ handelt. Jedenfalls ist es so nachzulesen im Buch von Jesse Liberty. Die Deutsche übersetzung heist:
Jetzt lerne ich C++, Markt & Technik Verlag, 2000
-
norman_timo schrieb:
da ich von der C# Welt komme, kenne ich dort zumindest das konkrete Beispiel die Methode ToString(), die JEDEM Objekt vererbt wird.
So ist das Problem, wenn ich diese Methode irgendwo fest überschreiben würde, dann wäre bei einem Cast auf ein hierarchisch höher liegenenden Typ die Eigenschaft verdreht, die die Methode eigentlich liefern sollte.
Also z.B. wenn ich bei einem UrUrUrVater die Methode aufrufe, könnte das eine andere Wirkung zeigen, wie wenn ich das von dem KindKindKind Objekt tun würde. Ein "Backcast" auf den UrUrUrVater sollte hier auch die ursprüngliche Methode liefern, weil sie z.B. in dessen Kontext sinnvoller ist.
Ich denke trotzdem, dass dies nicht sinnvoll ist, zumindest in C++ (für C# kann ich das nicht beurteilen). Denn durch einen Cast veränderst du das ursprünglich erstellte Objekt ja nicht. Du "interpretierst" es lediglich in einem engeren (Upcast) oder weiteren (Downcast) Kontext neu. Also wäre es auch unlogisch, wenn ein und dieselbe Funktion plötzlich was ganz anderes macht. Damit geht einfach ein Grundprinzip von OO verloren, indem du halt nicht mehr objektorientiert, sondern typorientiert denkst.
norman_timo schrieb:
Nichtsdestotrotz, wenn ich mit einem Pfeil durch die Brust ins Auge schießen muss, nur um diesen Effekt in C++ zu erreichen, dann überlege ich mir lieber einen anderen Designansatz

Ich wollte dir ja nur zeigen, dass es durchaus möglich ist. Empfehlen würde ich das aber nicht und ein anderer Designansatz ist auf jeden Fall der richtige Weg.
Knecht schrieb:
kann ich in C++ nicht immer auf eine Methode der Basisklasse zurückgreifen
Sofern public, ja. Damit brichst du aber im Beispiel das Open-Closed Prinzip, indem du Implementationsdetails freilegst, und ist daher nicht zu empfehlen.
-
groovemaster schrieb:
Knecht schrieb:
kann ich in C++ nicht immer auf eine Methode der Basisklasse zurückgreifen
Sofern public, ja. Damit brichst du aber im Beispiel das Open-Closed Prinzip, indem du Implementationsdetails freilegst, und ist daher nicht zu empfehlen.
Klassen-Methoden sind doch in der Regel Öffentlich um dem Benutzer Zugriff auf private Element einer Klasse, in einem Vorgegebenen Rahmen zu ermöglichen. Eine Hirarchie/Vererbung kann ich aufbauen, wenn zwei Dinge verwand sind.
Z.B. ist ein Kreis eine sonderform der Ellipse. Ich kann also eine Kreis-Klasse von der Ellipsen-Klasse ableiten und die Methode zur Berechnung der Fläche der Ellipse (a*b*π) verbergen durch die Spezialisierung für den Kreis (r2*π) die angemessener und den meisten Menschen vertrauter ist. Deswegen ist es aber nicht prinzipiell "falsch" auf die Formel der Ellipsenfläche zurückzugreifen. Die liefert, vielleicht etwas umständlicher da nicht so spezialisiert, das richtige Ergebnis.
Deswegen hab ich aber doch noch keine Implementierungsdetails offengelegt, da ja beide Flächenberechnungs-Methoden "Zugriffs"-Methoden sind. Oder?!?

-
Doch, dadurch hast du Implementationsdetails offen gelegt. Du denkst zu sehr kontextbezogen und zu wenig allgemein. In deinem Beispiel mag es zwar egal sein, ob du a.flaeche(x) oder a.ellipse::flaeche(x, x) schreibst, da beides das gleiche Ergebnis liefert. Der entscheidende Punkt ist aber, dass du einen Kreis hast und diese Klasse eine Funktion flaeche() breitstellt. Du rufst dementsprechend kreis.flaeche() auf und nichts anderes. Was intern passiert, weisst du nicht und hat dich auch überhaupt nicht zu interessieren. Es ist eben die Angelegenheit der Klasse Kreis, wie sie die Funktion flaeche implementiert. Sie kann die Funktion der Basisklasse aufrufen, einen eigenen Algorithmus definieren, nebenbei noch die Lottozahlen checken ... wissen wir alles nicht. Für uns ist die Funktion eine Black Box, wir geben was rein und bekommen was raus. Diese Schnittstelle ist fest und wird nicht geändert. Halt das "Closed"
geschlossen für Veränderungen. Die Funktion flaeche kann intern jederzeit geändert werden, zB ein neuer Algorithmus verwendet werden. Client Code wird dadurch aber nicht obsolet.
-
So hab ich's noch gar nicht gesehen!!!
Danke für den Hinweis
