Vector, Vererbte Klasse und der Copy Constructor
-
Hallo zusammen,
nachdem ich dachte ich hätte OOP verstanden kommt mir nun die STL in die Quere, denn während meine Polymorphie bei Einzelobjekten anstandlos funktioniert, funktioniert sie in einer <vector> Liste nicht mehr. Meine "ShowName" Funktion wird in der <vector> Liste nicht mehr von der "Car" Klasse benutzt, sondern von der "Vehicle" Klasse.
Folgendes Beispiel-Programm veranschaulicht mein Problem. Der Output des Programms ist unten angefügt. Ich vermute das ich Schwierigkeiten mit meinem Copy Konstruktor habe...
#include <iostream> #include <vector> using namespace std; class vehicle { public: virtual ~vehicle() { fprintf(stderr,"Destroying the \"vehicle::%s\" !\n",cName); delete[] cName; cName=NULL; } vehicle(const class vehicle &moep) { fprintf(stderr,"Copy the \"vehicle::%s\"\n",moep.GetName()); this->SetName(moep.GetName()); } vehicle() { cName=NULL; fprintf(stderr,"Create a \"vehicle\"\n"); } bool SetName(const char *Name) { if (cName!=NULL) { delete[] cName; cName=NULL; } cName = new char[strlen(Name)+1]; strcpy(cName,Name); return true; } const char *GetName() const { return cName; } virtual void ShowName() const { fprintf(stderr,"I am the vehicle \"%s\"\n",cName); } private: char *cName; }; class car:public vehicle { public: virtual ~car() { fprintf(stderr,"Destroying the \"car::%s\" !\n",this->GetName()); } car(const class car &moep):vehicle(moep) { fprintf(stderr,"Copy the \"car::%s\"\n",moep.GetName()); this->SetName(moep.GetName()); this->setHorsePower(moep.getHorsePower()); } car() { uiPS=15; fprintf(stderr,"Create a \"car\"\n"); } void setHorsePower(const unsigned int PS) { uiPS = PS; } const unsigned int getHorsePower() const { return uiPS; } virtual void ShowName() const { fprintf(stderr,"I am the car \"%s\" and i got \"%d\" horse power\n",this->GetName(),uiPS); } protected: unsigned int uiPS; }; int main () { // Checking vector list behavior class vehicle myVehicle; myVehicle.SetName("Transformer"); myVehicle.ShowName(); class car myCar; myCar.SetName("Kitt"); myCar.ShowName(); class vehicle *vec = NULL; vec = &myVehicle; vec->ShowName(); vec = &myCar; vec->ShowName(); vector<class vehicle> myVehiclePark; myVehiclePark.push_back(myVehicle); myVehiclePark.push_back(myCar); fprintf(stderr,"There are %ld vehicle in my park :)\n",myVehiclePark.size()); vector<class vehicle>::const_iterator iter; iter = myVehiclePark.begin(); for( ; iter != myVehiclePark.end(); ++iter) { iter->ShowName(); } return 0; }Der Output ist
// Instanzierung Create a "vehicle" I am the vehicle "Transformer" Create a "vehicle" Create a "car" I am the car "Kitt" and i got "15" horse power // Veranschaulichung der Polymorphie I am the vehicle "Transformer" I am the car "Kitt" and i got "15" horse power // Aufruf der Copy Konstruktoren für die <vector> Liste, hier wird auch der falsche Ctor aufgerufen ?! Copy the "vehicle::Transformer" Copy the "vehicle::Transformer" Copy the "vehicle::Kitt" // Wieso wird hier schon ein Objekt zerstört ? Destroying the "vehicle::Transformer" ! // Output der <vector> Liste There are 2 vehicle in my park :) I am the vehicle "Transformer" I am the vehicle "Kitt" // >> hier sollte eher "I am the car "Kitt" and i got "15" horse power" erscheinen // Vernichtung der selbstständigen Objekte und die in der <vector> Liste Destroying the "vehicle::Transformer" ! Destroying the "vehicle::Kitt" ! Destroying the "car::Kitt" ! Destroying the "vehicle::Kitt" ! Destroying the "vehicle::Transformer" !Was mache ich falsch ?
Winn
-
Polymorphie funktioniert nur über Zeiger und Referenzen (letztere können aber nicht in einen vector<> gepackt werden). Du speicherst die Objekte direkt per Wert in deinen vector<> - und dabei wird der 'car'-Anteil des Objekts abgeschnitten (sog. "Slicing").
(PS: Das Objekt, das beim/nach dem vector-Füllen zerlegt wird, ist das zweite 'Copy the "vehicle::Transformer"' - das hängt vermutlich damit zusammen, daß der vector<> seine Kapazität überschritten hat und alle Elemente umkopieren mußte)
-
CStoll schrieb:
Polymorphie funktioniert nur über Zeiger und Referenzen (letztere können aber nicht in einen vector<> gepackt werden). Du speicherst die Objekte direkt per Wert in deinen vector<> - und dabei wird der 'car'-Anteil des Objekts abgeschnitten (sog. "Slicing").
(PS: Das Objekt, das beim/nach dem vector-Füllen zerlegt wird, ist das zweite 'Copy the "vehicle::Transformer"' - das hängt vermutlich damit zusammen, daß der vector<> seine Kapazität überschritten hat und alle Elemente umkopieren mußte)
Grmpfs, hätte ich mir denken können... die Abänderung der "int main()" in
int main () { // Checking vector list behavior class vehicle myVehicle; myVehicle.SetName("Transformer"); myVehicle.ShowName(); class car myCar; myCar.SetName("Kitt"); myCar.ShowName(); class vehicle *vec = NULL; vec = &myVehicle; vec->ShowName(); vec = &myCar; vec->ShowName(); vector<class vehicle *> myVehiclePark; myVehiclePark.push_back(&myVehicle); myVehiclePark.push_back(&myCar); fprintf(stderr,"There are %ld vehicle in my park :)\n",myVehiclePark.size()); vector<class vehicle *>::const_iterator iter; iter = myVehiclePark.begin(); for( ; iter != myVehiclePark.end(); ++iter) { (*iter)->ShowName(); } return 0; }führt zum Erfolg. Allerdings bedeutet das doch auch, daß ich nun eine reine Pointer <vector> Liste besitze. Bei einer Annahme meine main() {} wäre nun eine Funktion foo() {} so würden doch alle Objekte nach der letzten Klammer } vernichtet werden und die Pointer zeigen ins Nirvana. Für mich bedeutet das, daß ich eine Klassehierachie in einer <vector> Liste nur als "dynamische" Objekte einbinden kann. Stimmt das ?
Danke schonmal !!
-
Woher du die Elemente bekommst, ist dem vector egal - du mußt nur dafür sorgen, daß sie länger "überleben" als der vector, sonst bleiben nur Zeiger auf unbenutzten Speicher zurück.
(wenn du Probleme mit der dynamischen Speicherverwaltung siehst, nimm doch Smart-Pointer wie boost::shared_ptr* oder die Pointer-Container der Boost-Bibliothek)
* vector<auto_ptr<vehicle> > geht nicht, weil ein auto_ptr nicht "normal" kopierbar ist.