Bietet Private-Vererbung irgendwelche Vorteile gegenüber Komposition?
-
Beides würde für den Programmierer einer Klasse die gleichen Möglichkeiten bieten, bei eomer Komposition könnte man das assoziierte Objekt zur Laufzeit austauschen, was ein klein wenig mehr Flexibilität bringen kann. Hat die Private-Vererbung auch irgend einen Vorteil, oder ist sie eigentlich komplett überflüssig?
-
Son of a Bitch schrieb:
Beides würde für den Programmierer einer Klasse die gleichen Möglichkeiten bieten,
Ja, auf den ersten Blick schon.
Son of a Bitch schrieb:
bei eomer Komposition könnte man das assoziierte Objekt zur Laufzeit austauschen, was ein klein wenig mehr Flexibilität bringen kann.
Ja, aber wer braucht das schon?
Son of a Bitch schrieb:
Hat die Private-Vererbung auch irgend einen Vorteil, oder ist sie eigentlich komplett überflüssig?
Bei Vererbung werden alle neuen Sachen automatisch reingeerbt. Das ist eine sehr starke Bindung. Man muß schon viel Mut haben, um die einzugehen.
Allgemein kann man sagen, daß private Erblichkeit Quatsch ist. Sie wird nur angestrengt, um Schwächen der Sprache zu umgehen oder auszunutzen, zum Bleistift die Empty Member Optimization. Manche Anfänger benutzen private Erblichkeit sogar, um drei oder vier triviale einzeilige Forwarder nicht tippen zu müssen.http://www.c-plusplus.net/forum/viewtopic-var-t-is-75672.html
-
volkard schrieb:
...
Allgemein kann man sagen, daß private Erblichkeit Quatsch ist....

Das ist mal eine prägnante Aussage, die man sich gut merken kann.Danke,
Simon2.
-
Simon soo pauschal sollte man sich das nicht merken - wenn dann den ganzen Satz:
volkard schrieb:
Allgemein kann man sagen, daß private Erblichkeit Quatsch ist. Sie wird nur angestrengt, um Schwächen der Sprache zu umgehen oder auszunutzen, zum Bleistift die Empty Member Optimization.
Beispiele solcher Dinge wo private Vererbung sind machen kann:
- EBCO (wie schon genannt)
- Zugriff auf protected Member/Methoden der Basisklasse
- Überladen von virtuellen Methoden und Zugriffsgewährung an ausgesuchte Klassen (ich glaub Sutter nennts "controlled polymorphism"):class Base { virtual void foo(); }; class BigBoss; class NotReallyDerived : private Base //offiziell bin ich kein Base,... { virtual void foo(); friend class BigBoss; //... aber BigBoss darf mich als eins benutzen! };
-
pumuckl schrieb:
Simon soo pauschal sollte man sich das nicht merken ...
Doch ... so wie "Bei Rot nicht über die Ampel".
Eine gute Richtlinie, von der man nur in begründeten Ausnahmen abweicht.Die "Ampelregel" gilt auch nicht in jedem Einzelfall - wenn z.B. der führerlose LKW auf dich zudonnert oder Du Deine in den Wehen liegende Frau nachts um 3h auf der einsamen Landstraße ins Krankenhaus bringen willst, kann es besser sein, diese Regel zu brechen.
pumuckl schrieb:
- wenn dann den ganzen Satz:
Naja - für mich endet ein Satz beim nächsten Punkt...

Ich denke sowieso, dass es im Deutschen ein Problem mit dem Begriff "im Allgemeinen" gibt.
Manchmal ist damit gemeint: "in 90% der Fälle" und manchmal (wie oft in der Mathematik) "in jedem Zusammenhang". Ich habe o.G. im ersten Sinn verstanden und bin dir dankbar für Beispiele für die restlichen 10%.Gruß,
Simon2.
-
Naja, okay, du machst ne 90%-Regel draus. Oft wird hier im Forum aber aus sowas eine 99%-Regel gemacht wobei das restliche Prozent dann unter den Tisch fällt und es sich immer liest als wäre der allgemeine Satz die einzige unumstößliche Wahrheit
Und dem ist eben nicht so.
-
Ich hatte nicht den Eindruck, dass volkard das so gemeint hatte ... aber es ist auf jeden Fall gut, dass Du das noch einmal präzisiert hast.
Gruß,
Simon2.
-
Abgesehen von den bereits genannten Punkten finde ich
private-Vererbung noch praktisch, um von Dingen wieboost::noncopyablezu erben.
-
zwei weitere Punkte, entnommen aus Sutter/Alexandrescu's C++ Coding Standards:
benutze Vererbung, wenn:
- das benutze Objekt vor einer anderen Basisklasse konstruiert oder nach ihr zwerstört werden muss
- es im Zusammenhang mit virtuellen Basisklassen nötig ist.
-
Was haltet ihr eigentlich davon, privat abzuleiten und einzelne Funktionen mittels
usingöffentlich zu machen? So verhindert man, dass das Objekt als Basisklasseninstanz angesprochen wird, kann aber andere Vorteile der Vererbung nutzen.Selbst habe ich das noch nie so gemacht, allerdings auch schon bei fremden Code gesehen.
-
Nexus schrieb:
Was haltet ihr eigentlich davon, privat abzuleiten und einzelne Funktionen mittels
usingöffentlich zu machen? So verhindert man, dass das Objekt als Basisklasseninstanz angesprochen wird, kann aber andere Vorteile der Vererbung nutzen.Meistens dürfte gelten: Dazu müßte eigentlich gelten Derived IST EIN Base. Anderenfalls müßte man immer stets ununterbrpchen aufpassen, ob das geusingte noch gültig ist. Und wenn man eh IST EIN hat, kann man auch gleich öffentlich erben.
-
Kann es nicht sinnvoll sein, auf diese Weise Codeduplizierung zu vermeiden? Oder hältst du eine Aggregation immer für angebrachter?
Ein ausgedachtes Beispiel: Zwei Klassen in einem GUI-Framework,
PanelundWindow.Panelist eine Unterteilung des Fensters und kann selber beliebige GUI-Komponenten (auch anderePanels) aufnehmen.Windowsoll das auch können, aber es muss zuoberst stehen und darf nicht als Bestandteil anderer Komponenten fungieren (darf also nicht alsPanelbehandelt werden). Deshalb könnte es privat vonPanelerben und die gemeinsamen Funktionen öffentlich machen.Hmm... Ganz sauber kommt mir das selber nicht vor, zumal hier gegen Aggregation nicht wirklich etwas spricht.

Ich wäre trotzdem froh um Meinungen dazu, mir fällt leider kein besseres Beispiel ein. Wenn die Beschreibung etwas ungenau war, kann ich das Beispiel gerne an einem Stück Code illustrieren.
-
Hmm. Ich würde das wahrscheinlich eher so lösen, dass ich eine Klasse
Containerdefiniere und dann kannst du da Window und Panel davon ableiten, da beide als Container fungieren und somitContainersind. (Das ist ja deine grundsätzliche Aussage oben dasWindowundPanelContainer sind).
-
Man kann damit Designschwächen anderer Bibliotheken ausbügeln:
Nämlich immer dann, wenn man eine Aggregation will, aber protected member des Objektes braucht, dann ist die private Vererbung das Einzige, was einen rettet.
-
otze schrieb:
Man kann damit Designschwächen anderer Bibliotheken ausbügeln
Jup. Wohl die Hauptanwendung.
-
drakon schrieb:
Hmm. Ich würde das wahrscheinlich eher so lösen, dass ich eine Klasse
Containerdefiniere und dann kannst du da Window und Panel davon ableiten, da beide als Container fungieren und somitContainersind. (Das ist ja deine grundsätzliche Aussage oben dasWindowundPanelContainer sind).Panelwürde aber von einer zusätzlichen (abstrakten) Basisklasse für alle GUI-Komponenten erben, sagen wirComponent. Elementare Komponenten (nennen wir sie Widgets) wie Schaltflächen werden ebenfalls von dieser Klasse abgeleitet.Wäre hier Mehrfachvererbung angebracht?
+-----------+ +-----------+ | Container | | Component | +-----------+ +-----------+ ^ ^ | | +------+-------+ +-------+-------+ | | | | +-----------+ +-----------+ +-----------+ | Window | | Panel | | Widget | +-----------+ +-----------+ +-----------+
-
Ja, Mehrfachvererbung empfinde ich durchaus als einen guten Lösungsansatz. (Potentiell gibt es sogar noch mehr, von denen du erben kannst, wenn man wirklich eine GUI Library erstellt).
-
drakon schrieb:
Potentiell gibt es sogar noch mehr, von denen du erben kannst, wenn man wirklich eine GUI Library erstellt.
Ich will nicht eine komplette GUI schreiben, eher was Kleines für SFML, vor allem für alltägliche Dinge. Erweitern kann ich es immer noch. Gerade auch deshalb habe ich mir vorgenommen, von Anfang an auf schönes Design zu achten.
Klar könnte man noch mehr machen. Ich versuche aber, allzu tiefe Klassenhierarchien zu vermeiden und die Zusammenhänge - sofern es geht - einfach zu halten. Im Gegensatz zu vielen GUIs in C++ möchte ich dem Anwender auch die Möglichkeit geben, die Komponenten selbst zu verwalten. Also vorerst nichts mit Pseudo-Garbage-Collector.

Das mit dem
Containermuss ich mir noch überlegen. So eine abstrakte Basisklasse macht vor allem Sinn, wenn man verschiedene abgeleitete Klassen gemeinsam ansprechen will, dafür fehlen mir gerade Anwendungsfälle. Was ich mir auch überlege, ist eine Aggregation, also dass das Fenster ein Standard-Panel besitzt (das eben das ganze Fenster ausfüllen würde). Um an diesem Änderungen vorzunehmen, könnte ich entweder Methoden wrappen, eine Referenz auf das interne Panel zurückgeben (nicht besonders sauber) oder eben private Vererbung benutzen. Letzteres scheint mir aber wie gesagt ebenfalls nicht ganz das Wahre zu sein...Oder ich lasse den Benutzer das Panel selbst erstellen und verweise im Fenster lediglich darauf. Somit ist er flexibler. Das ist allerdings mühsam, weil man zu jedem Fenster gleich ein Panel erstellen muss, um es überhaupt benutzen zu können.
-
Die Sache mit der privaten Vererbung, um dann einfach per using die geerbten Methoden zu veröffentlichen ist natürlich sehr verlockend, weil man dann nicht die ganzen Methoden nach Schema F definieren und an das Member durchreichen muss. Die Semantik sit wie volkard gesagt hat aber eben eine ganz andere.
Für sowas würde ich mir ein neues Sprachelement wünschen:class A { int foo(); char foo(int i); string bar(int a, bool b, char c); }; //böse: class B : private A { public: using A::foo; using A::bar; }; //richtig, aber aufwändig und langatmig: class C { A theA; public: int foo() { return theA.foo(); } char foo(int i) { return theA.foo(i); } string bar(int a, bool b, char c) { return theA.bar(a,b,c); } }; //schön wärs: class D { A theA; public: expose theA.foo; expose theA.bar; };
-
Ich finde es nicht nachvollziehbar, sich im Falle privater Vererbung mit der Definition "IST-EIN" aufzuhalten und dann von diesem Standpunkt aus private Vererbung zu beurteilen.
Im Falle öffentlicher Vererbung halte ich IST-EIN für ein brauchbares Kriterium, bei privater Vererbung aber ist es Unsinn. Wie wäre es stattdessen mit IST-IMPLEMENTIERT-MIT (oder ähnlichem)? Dann wäre auch an Nexus' Vorschlag der Übernahme von Funktionen privater Oberklassen per using nur noch wenig auszusetzen.
Der Sinn von expose erschließt sich mir nicht. Was ist der Vorteil gegenüber der using-Lösung? Abgesehen halt vom IST-EIN-"Problem".
Stefan.
-
DStefan schrieb:
Ich finde es nicht nachvollziehbar, sich im Falle privater Vererbung mit der Definition "IST-EIN" aufzuhalten und dann von diesem Standpunkt aus private Vererbung zu beurteilen.
Im Falle öffentlicher Vererbung halte ich IST-EIN für ein brauchbares Kriterium, bei privater Vererbung aber ist es Unsinn. Wie wäre es stattdessen mit IST-IMPLEMENTIERT-MIT (oder ähnlichem)? Dann wäre auch an Nexus' Vorschlag der Übernahme von Funktionen privater Oberklassen per using nur noch wenig auszusetzen.der main() kannst du sowas meinetwegen erzählen. aber glaubt die erbende klasse das denn auch? klares nein.
und wozu erben, wenn's nicht not tut? das übt doch nur unnötig druck auf die klassenhierarchie (taxonomie!) aus und führt dann zu mehrfachen erblichkeitsproblemen.