Von STL Container erben?
-
Hallo,
sollte man von STL Containern erben (z.B. von std::vector?) ? Weil ich habe öfter Situationen, in denen es praktisch wäre, wenn sich die Klasse genau so wie ein STL Container verhält, z.B. eine Vector Klasse (für Vectoren im mathematischen Sinne. Dadurch lässt sich Addieren und andere Operationen, die für jede Komponente des Vektors durchgeführt werden müssen, ganz einfach mit std::transform erledigen. Oder sollte man in so einem Fall lieber eine öffentlich Methode schreiben, die Zugriff auf den darunter liegenden Container ermöglicht (in dem Beispiel std::array) ? Oder besser die Funktionen des Arrays einfach weiterleiten (also z.B. eine öffentliche Methode begin anbieten die intern std::array::begin verwendet) ?
-
Wie in einem anderen Thread erwähnt - Falls ich mich nicht irre : Definitiv nicht, weil sie nie als Basisklassen ausgelegt worden sind -> Virtueller Destruktor fehlt, dadurch kommt man schnell in UB, wenn man nicht aufpasst.
-
Ich möchte die Klassen ja auch nicht in einem Zeiger auf std::vector speichern. Möglicherweise auch private Vererbung mit einer Reihe von using-direktiven?
-
Wie in meinem anderen Thread schon gesagt: Was willst du durch (public-)Erben von einer Klasse erreichen, die keine protected oder virtual Member hat? Du erweiterst doch bloß die Funktionalität des public-Interfaces. Und dazu wurden Funktionen erfunden.
-
SeppJ schrieb:
Wie in meinem anderen Thread schon gesagt: Was willst du durch (public-)Erben von einer Klasse erreichen, die keine protected oder virtual Member hat? Du erweiterst doch bloß die Funktionalität des public-Interfaces. Und dazu wurden Funktionen erfunden.
also einfach sowas?
template <std::size_t N, class T> using Vector = std::array<T, N>;
-
Mir fehlt der Kontext um zu verstehen, was du damit sagen möchtest.
-
SeppJ schrieb:
Du erweiterst doch bloß die Funktionalität des public-Interfaces. Und dazu wurden Funktionen erfunden.
In meinen Vorlesungen wurde beigebracht, dass genau das der Sinn von Vererbung sein soll.
Was willst du durch (public-)Erben von einer Klasse erreichen, die keine protected oder virtual Member hat?
Gemäß der allgemeinen Richtlinie,
protected
Member praktisch nicht zu verwenden, hört sich deine Aussage an, als ob man (public
) Vererbung hauptsächlich nur dann benutzt, wenn Polymorphie gebraucht wird. Ist dem so?
-
Gugelmoser schrieb:
SeppJ schrieb:
Du erweiterst doch bloß die Funktionalität des public-Interfaces. Und dazu wurden Funktionen erfunden.
In meinen Vorlesungen wurde beigebracht, dass genau das der Sinn von Vererbung sein soll.
In der Uni sagt man vieles, was sich in der Praxis nicht unbedingt als gut heraus gestellt hat. Vererbung ist durchaus sinnvoll, wird aber in der Praxis viel zu häufig an Stellen verwendet, wo man besser andere Mittel hätte verwenden sollen (z.B Komposition...).
Vererbung ist eine der stärksten Bindungen (In C++ gibt es noch eine stärkere Bindung: friend), um so stärker eine Bindung ist, um so schwerer ist es bei einer Designänderung den Code umzustellen und reduziert damit teilweise die Wartbarkeit.
Vererbung ist ein starres Konstrukt, und gerne werden von unerfahrenen oder unbedachten Programmierern tiefe Vererbungshierarchien erstellt, und eine Kombination verschiedener Vererbungsbäume miteinander ist nur schwer wartbar zu realisieren. C++ erlaubt zwar eine Mehrfachvererbung, dies kann aber zu anderen Problemen führen.
Nutze daher Vererbung weise, und prüfe vorher ob es sinnvolle Alternativen gibt. Zudem sollte die Basisklasse in C++ einen virtuellen (oder nicht öffentlichen) Konstruktor besitzen. Man sollte zudem das Liskovsche Substitutionsprinzip beachten.
Es gibt in C++ noch ein paar Techniken die mittels Templates einige der Nachteile entkräften, da man die Klassen "konfigurierbar" machen kann (Policy Based Design), dies ist aber eine (seltene) Sonderform der Vererbung.
-
SeppJ schrieb:
Wie in meinem anderen Thread schon gesagt: Was willst du durch (public-)Erben von einer Klasse erreichen, die keine protected oder virtual Member hat? Du erweiterst doch bloß die Funktionalität des public-Interfaces. Und dazu wurden Funktionen erfunden.
Und was macht man mit Operatorüberladung? Für Vektoren z.B. möchte man ja gerne die +, -, *, /, ... Operatoren überladen. Dann kann man, wenn man für Vektoren einfach std::vector oder std::array nimmt und die Operatoren als freie Funktionen implementiert, unlogische Sachen machen (z.B. += auf std::array oder vector die gar keine Vektoren darstellen sollen).
-
pyhax schrieb:
SeppJ schrieb:
Wie in meinem anderen Thread schon gesagt: Was willst du durch (public-)Erben von einer Klasse erreichen, die keine protected oder virtual Member hat? Du erweiterst doch bloß die Funktionalität des public-Interfaces. Und dazu wurden Funktionen erfunden.
Und was macht man mit Operatorüberladung? Für Vektoren z.B. möchte man ja gerne die +, -, *, /, ... Operatoren überladen. Dann kann man, wenn man für Vektoren einfach std::vector oder std::array nimmt und die Operatoren als freie Funktionen implementiert, unlogische Sachen machen (z.B. += auf std::array oder vector die gar keine Vektoren darstellen sollen).
Deswegen macht man das ja auch nicht, da das was der std::vector und das std::array darstellen keine sinnvollen arithmetischen Operatoren haben. Daher schreibt man eine eigene Klasse dafür. Und die erbt dann nicht von array oder vector (zumindest nicht public, eventuell aber private), sondern hat einen Member der vector oder array ist.
Dein Argument ist also quasi, dass schlechtes Design ok ist, weil an anderer Stelle auch schlechtes Design möglich ist.
-
pyhax schrieb:
SeppJ schrieb:
Wie in meinem anderen Thread schon gesagt: Was willst du durch (public-)Erben von einer Klasse erreichen, die keine protected oder virtual Member hat? Du erweiterst doch bloß die Funktionalität des public-Interfaces. Und dazu wurden Funktionen erfunden.
Und was macht man mit Operatorüberladung? Für Vektoren z.B. möchte man ja gerne die +, -, *, /, ... Operatoren überladen.
Wofür denn das? Operatoren-Überladung da, wo der Sinn vom Kontext her ersichtlich ist. so lautet mein Verständnis. HIer ist vielleicht
+=
noch akzeptabel (->push_back). Aber das was einstd::vector
macht ist nicht dasselbe, was vielleicht ein Vektor macht...