Containerklasse mit polymorphen Objekten
-
Hallo,
irgendwie stehe ich gerade auf'm Schlauch und komm nicht auf eine einfache Lösung. Ich brauche für mein Problem eine Containerklasse die polymorphe Objekte verwaltet. Jetzt frage ich mich, wie kriege ich diese Objekte möglichst anwenderfreundlich an den Container übergeben. Das beste was mir bisher eingefallen ist, ist die Arbeit mit Templates, ungefähr so:
class base{ protected: int element; public: base(const int &tt):element(tt){}; virtual ~base(){}; virtual void method()=0; }; class derived1: public base{ public: derived1(const int &tt):base(tt){}; virtual ~derived1(){}; void method(){ cout<<"Derived1 "<<element<<endl; } }; class derived2: public base{ public: derived2(const int &tt):base(tt){}; virtual ~derived2(){}; void method(){ cout<<"Derived2 "<<element<<endl; } }; class container{ private: vector<base*> list; public: ~container(){ for (int i=0; i<list.size();++i){ delete(list[i]); } } template<class T> void add(const T& bb){ list.push_back(new T(bb)); } void output(){ for (int i=0; i<list.size();++i){ (*list[i]).method(); } } }; int main(){ container cont; cont.add<derived1>(derived1(1)); cont.add<derived2>(derived2(2)); cont.output(); }(Ja, ich weiß. Ich habe hier die Regel der großen Drei nicht beachtet, aber ich wollte das Beispiel jetzt nicht unnötig aufblähen)
Das ganze kommt mir unnötig umständlich vor. Gibt es da eine Möglichkeit, dass der Nutzer des Containers einfach sowas wie
cont.add(derived1(1));schreiben kann? Wenn die add-Methode statt eines Template-Parameters ein Element der Basisklasse erwartet, geht das ja nicht, weil diese abstrakt ist.
Ich habe schon daran gedacht, die add-Methode für alle abgeleiteten Klassen zu überschreiben, aber dies ist keine praktikable Lösung, weil der Nutzer später eigene abgeleitete Klassen implementieren können soll, ohne dafür am Code der Containerklasse rumzufummeln.
Wie kann man dies geschickter machen?
-
was genau stoert dich an
cont.push_back(new Foo());?
-
Shade Of Mine schrieb:
was genau stoert dich an
cont.push_back(new Foo());?
Wenn ich den so übergebenen Zeiger direkt speichere könnte der Anwender das Objekt später löschen, obwohl es ja eigentlich private-Inhalt des Containers werden soll. Also müsste ich eine Kopie davon anlegen - aber welchen Konstruktor soll ich dann nehmen? Ich weiß ja nicht, was da übergeben wurde.
-
SeppJ schrieb:
Wenn ich den so übergebenen Zeiger direkt speichere könnte der Anwender das Objekt später löschen, obwohl es ja eigentlich private-Inhalt des Containers werden soll. Also müsste ich eine Kopie davon anlegen - aber welchen Konstruktor soll ich dann nehmen? Ich weiß ja nicht, was da übergeben wurde.
es ist auch moeglich ein
std::vector<Foo> v;
v.push_back(Foo());
v[0].~Foo();zu machen. Ist es deshalb sinnvoll dass v[0] eine Kopie zurueck gibt?
Wenn du einsiehst dass hier eine referenz einfach Sinn macht, dann wirst du feststellen dass es bei deinem zeiger beispiel nicht anders ist.
du kannst dich nie gegen jede dummheit schuetzen. das macht auch keinen sinn.
wenn du unbedingt diesen einen fehler verhindern willst (ein delete vec[0]; ist aber dennoch immernoch moeglich) dann musst du eine clone-System wie zB in Java implementieren. Das erste was du aber ueber clone in Java oder sonstwo hoerst ist: benutz es nur wenn es wirklich nicht anders geht und selbst dann meide es wenn irgend moeglich. (etwas ueber dramatisiert).
clone-Systeme sind fehleranfaellig und umstaendlich zu implementieren. die richtige variante ist es dem anwender des codes zu vertrauen.
-
Danke, deine Argumente haben mich überzeugt. So werde ich es dann machen.