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.


Anmelden zum Antworten