std::vector - Ableitung/Komposition
-
Hallo zusammen,
ich hoffe meine Frage ist nicht allzu dumm... :?
Es geht darum, das ich einen std::vector als Komposition benutzen möchte aber nicht weiß, wie ich dann über einen range iterieren kann.
Beispiel wenn ich ableiten - ich weiß, dass ich die Klasse wegen des fehlenden viruellen Destruktors dann nicht polymorph verwenden kann:
template <class T> class MyVector : public std::vector<T>
jetzt kann ich natürlich problemlos über eine Range iterieren:
MyVector<int> v; for ( int i : v) {.....
Jetzt will ich den Vekor aber als Komposition benutzen (sagt man das so?):
template <class T> class MyVector { private std::vector<T> vec;
Wie kann ich nun über einen Bereich iterieren, also genau wie zuvor:
MyVector<int> v; for ( int i : v) {.....
Vielen Dank für eure Hilfe
-
Graythorn schrieb:
ich hoffe meine Frage ist nicht allzu dumm... :?
Das ist sie nicht.
Komposition:
template<class T> class MyVector { public: typedef typename std::vector<T>::iterator iterator; typedef typename std::vector<T>::const_iterator const_iterator; ... iterator begin() { return data.begin(); } iterator end() { return data.end(); } const_iterator begin() const { return data.begin(); } const_iterator end() const { return data.end(); } ... private: std::vector<T> data; };
So ist das aber etwas mühselig. Man müsste für "..." noch den Rest der Schnittstelle kapseln, damit der Nutzer auch was von seinem
MyVector
hat.Alternativ ginge auch "implementation inheritance":
template <class T> class MyVector : private std::vector<T> { typedef std::vector<T> stdvec; public: // ein paar typedefs aus der Basisklasse zur Verfügung stellen using iterator = typename stdvec::iterator; using const_iterator = typename stdvec::const_iterator; using reference = typename stdvec::reference; using const_reference = typename stdvec::const_reference; using size_type = typename stdvec::size_type; // ein paar methoden aus der Basisklasse zur Verfügung stellen using stdvec::stdvec; // Konstruktoren using stdvec::begin; using stdvec::end; using stdvec::insert; using stdvec::erase; using stdvec::size; using stdvec::push_back; // mal selbst dazwischen funken reference operator[](size_type index) { std::cout << "huhu\n"; return stdvec::operator[](index); } };
Man leitet also privat ab. Damit sind auch automatisch alle Member der Basisklasse privat. Der Nutzer kann jetzt nicht mehr aus einem
MyVector<T>*
einstd::vector<T>*
machen. Per using-Deklarationen, kann man dem Nutzer aber einige Member wieder zur Verfügung stellen. Ist eine Funktion überladen, schließt das auch gleich alle Überladungen mit ein (mehrere Konstrucktoren, beide push_back Varianten, etc). Das ist also weniger schreibaufwändig.Und selbst "public inheritance" ist eigentlich nicht so schlimm. Es kommt ein bisschen drauf an, was Dein
MyVector
anders machen soll. Wenn es nicht schlimm ist, dass der Nutzer direkt an die Basisklasse dran kann, dann kannst du auch öffentlich erben. Polymorph ist da dann nichts. Aber das wäre nur dann schlimm, wenn Du ein dynamisch erzeugtenMyVector
über einenstd::vector
zeiger löschen willst. Wenn Du das vermeidest, ist alles OK. Mit public inheritance würdest Du dir diese using-Deklarationen sparen. Ist jetzt nicht "schön", aber geht.
-
Ich habe mal vor einer halben Ewigkeit obiges als notwendig beschrieben, und volkard antwortete prompt, dass es ein Design Fehler sei.
-
Arcoth schrieb:
Ich habe mal vor einer halben Ewigkeit obiges als notwendig beschrieben,
Was genau?
Arcoth schrieb:
und volkard antwortete prompt, dass es ein Design Fehler sei.
Zum Design kann ich jetzt nicht viel sagen. Ich weiß nicht, was Graythorn mit
MyVector
überhaupt erreichen will. Aber das ist mal eine gute Gelegenheit, nachzuhaken: Graythorn, was ist deine Motivation fürMyVector
?
-
template <class T> class MyVector : public std::vector<T> //Hier fehlt die Angbabe, was dazukömmt
template <class Tier> class MyZoo : public std::vector<Tier> //Designfehler
Auch wenn sich alle Tiere kopieren lassen, der Zoodirektor Grzimeck dann doch nicht. Da führt nur zu Ärger.
Du hast doch irgendwas vor, wenn Du von einem std::vector erben willst.
Was spricht bei Deinem konkreten Problem dagegen, zu sagen, daß Dein Zoo einen vector<Tiere> hat anstatt ein vector<Tiere> zu sein?
template <class Tier> class MyZoo { public std::vector<Tier> tiere; public: std::vector<Tier> const& getTiereView() const{//gucken darf jeder return tiere; } //Designfehler
Ich verstehe nicht, wie Du gleichzeitig "als Komposition" benutzen willst mit "for(auto& t:zoo)" statt "for(auto& t:zoo.getTiereView());". Wir hatten uns doch geeinigt, daß der Zoo nicht eine Ansammlung von Tieren IST. Warum es dann für die Schaleife voraussetzen?
-
Ein kl. Einschub:
Von STL Containern abzuleiten ist keine sonderlich gute Idee.vgl. Diskussion:
Nathan schrieb:
jb2603 schrieb:
Warum haben die STL Container kein virtuellen Destruktor?
Antwort: Sie haben keine virtuellen Funktionen und sind nicht als Basisklasse konzipiert. Man sollte deshalb auch nie von ihnen erben.
Q: https://www.c-plusplus.net/forum/335150?highlight=vector+virtual
-
Ich habe 3 Gründe, um den Container (hier vector) zu kapseln:
-
Ich habe einen älteren Programmcode zu warten, und der benutzt eben keinen STL-Container. Daher kapsele ich diesen, um die im alten Code benutzten Methoden nachzubilden. Nach und nach stelle ich so auf die STL-Container um.
-
Ich möchte einige spezielle Funktionalitäten hinzufügen.
-
Ich möchte die Klasse kapseln, um somit von einer speziellen Implementierung (hier STL) unabhängig zu sein.
Ich habe noch eine (Verständnis-)Frage an die Experten:
warum schreibe ich
typedef int myType_t;
aber
typedef typename std::vector<T>::iterator iterator;
also mal mit und mal ohne "typename"?
Wo ist der Unterschied, wann benötige ich "typename"?Danke für die Hilfe und Diskussion
-
-
Graythorn schrieb:
Wo ist der Unterschied, wann benötige ich "typename"?
-
Graythorn schrieb:
Ich habe 3 Gründe, um den Container (hier vector) zu kapseln:
Du unkapselst aber.
Den return-Typ von getTiereView() kannste frei bestimmen, es gibt kein Gesetz, daß es vector sein muss, glaube ich.