stl newbie::vector, copy konstruktor und vererbung



  • Hallo zusammen,

    ich versuche mich in die STL hineinzuarbeiten und habe zwei probleme bezogen auf den untigen Quellcode:

    1. Bekomme ich für meine "class vehicle" keinen copy konstruktor gebastelt, weil ich den Compiler Error nicht verstehe.

    /SourceCode/Vector and Inheritance/main.cpp:9: error: passing 'const vehicle' as 'this' argument of 'char* vehicle::GetName()' discards qualifiers

    1. Kann ich über das Vector-Array nicht auf meine vehicle Klasse bzw. Methoden zugreifen und verstehe auch hier den Compiler nicht wirklich.

    /SourceCode/Vector and Inheritance/main.cpp:50: error: 'class std::vector<vehicle, std::allocator<vehicle> >' has no member named 'ShowName'

    Jede Hilfe oder Anregung ist willkommen !?

    Winn

    Der "Trouble"-Code

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    class vehicle
    {
    public:
    	vehicle(const class vehicle &moep) { this->SetName(moep.GetName()); }
    	vehicle() { cName=NULL; fprintf(stderr,"Just a vehicle !\n"); }
    	~vehicle() { fprintf(stderr,"Destroying the vehicle \"%s\" !\n",cName); delete[] cName; cName=NULL; }
    
    	virtual bool isMoving() { fprintf(stderr,"hicl hicl...\n"); return true; }
    	bool SetName(char *Name) { if (cName!=NULL) { delete[] cName; cName=NULL; } cName = new char[strlen(Name)+1]; strcpy(cName,Name); return true; }
    	char *GetName() { return cName; }
    	void ShowName() { fprintf(stderr,"My name is \"%s\"\n",cName); }
    
    private:
    
    	char *cName;
    };
    
    class car:public vehicle
    {
    public:
    	// car() { fprintf(stderr,"This is a car !\n"); }
    	// ~car() { fprintf(stderr,"Destroying the car :S\n"); }
    
    	virtual bool isMoving() { fprintf(stderr,"wruuuuum wruuuuum....\n"); return true; }
    };
    
    int main (int argc, char * const argv[]) 
    {
    
    	class vehicle *myVehicle = new vehicle[1];
    	myVehicle->isMoving();
    	myVehicle->SetName("Transformer");
    
    	class car *myCar = new car[1];
    	myCar->isMoving();
    	myCar->SetName("Kitt");
    
    	vector<vehicle> *myVehiclePark = NULL;
    	myVehiclePark = new vector<vehicle>[1];
    
    	myVehiclePark->push_back(*myVehicle);
    	myVehiclePark->push_back(*myCar);
    
    	myVehiclePark[0].ShowName();
    
    	delete[] myVehiclePark;
    	delete[] myVehicle;
    	delete[] myCar;
    
    	return 0;
    }
    


  • #include <iostream>
    #include <string>
    #include <vector>
    using namespace std;
    
    class vehicle
    {
    public:
    	vehicle(const vehicle& moep) 
                : cName(moep.cName)
            { }
    
    	vehicle() 
                : cName("")
            { 
                cerr << "Just a vehicle !" << endl;
            }
    
    	virtual ~vehicle() 
            { 
                cerr << "Destroying the vehicle \"" << cName << "\" !" << endl;
            }
    
    	virtual bool isMoving() const
            { 
                cerr << "hicl hicl..." << endl;
                return true; 
            }
    
    	void SetName(const string& Name) 
            { 
                cName = Name;
            }
    
    	string GetName() const
            { 
                return cName;
            }
    
    	void ShowName() const
            { 
                cerr << "My name is \"" << cName << "\"" << endl;
            }
    
    private:
    	string cName;
    };
    
    class car : public vehicle
    {
    public:
    	car() 
            { 
                cerr << "This is a car !" << endl; 
            }
    
    	virtual ~car() 
            { 
                cerr << "Destroying the car :S" << endl;
            }
    
    	virtual bool isMoving() 
            { 
                cerr << "wruuuuum wruuuuum...." << endl; 
                return true; 
            }
    };
    
    int main (int argc, char * const argv[]) 
    {
    
    	vehicle myVehicle;
    	myVehicle.isMoving();
    	myVehicle.SetName("Transformer");
    
    	car myCar;
    	myCar.isMoving();
    	myCar.SetName("Kitt");
    
    	vector<vehicle*> myVehiclePark;
    	myVehiclePark.push_back(&myVehicle);
    	myVehiclePark.push_back(&myCar);
    
    	vector<vehicle*>::iterator iter = myVehiclePark.begin();
    	for( ; iter != myVehiclePark.end(); ++iter)
    	{
    	    (*iter)->ShowName();
    	}
    }
    


  • char *GetName() { return cName; }
    

    Ist nicht const-correct.

    Es musste ungefähr so aussehen:

    char* const GetName() const { return cName; }
    

    Dann funzt auch der Copy-Ctor.

    Gruß
    Don06


  • Mod

    Winn schrieb:

    1. Bekomme ich für meine "class vehicle" keinen copy konstruktor gebastelt, weil ich den Compiler Error nicht verstehe.

    /SourceCode/Vector and Inheritance/main.cpp:9: error: passing 'const vehicle' as 'this' argument of 'char* vehicle::GetName()' discards qualifiers

    vehicle::GetName ist eine nicht-konstante nicht-statische Memberfunktion. Das bedeutet, dass ihr Objektparameter nicht konstant ist. Ein normaler Copy-Konstruktor hat aber ein eine Referenz-auf-const als Parameter

    vehicle(const class vehicle &moep) { this->SetName(moep.GetName()); }
    

    hier ist moep konstant, GetName arbeitet mit nicht-konstanten Objekten, und ein Aufruf über moep würde also die const-Qualifikation von moep verwerfen, was nicht zulässig ist. Das ist der ganze Hintergrund der etwas merkwürdigen Fehlermeldung.
    Zur Abhilfe sollte GentName eine konstante Mmeberfunktion sein:

    char *GetName() const{ return cName; }
    

    Das const bewirkt, dass der Objektparameter konstant sein darf und innerhalb der Funktion this ein Zeiger auf ein konstantes Objekt ist. Damit ist durch die Sprache gesichert, dass GetName das Objekt nicht verändern kann (binäre Konstanz). Damit wird aber nur verhindert, dass innerhalb der Funktion der Pointer verändert wird, nicht das, worauf der Pointer zeigt (logische Konstanz) - und weil dieser Pointer direkt so weitergegebn wird, könnte auch ein Aufrufer von GetName den Namen verändern. Logische Konstanz ist erfahrungsgemäß vorzuziehen, deshalb sollte die GetName einen Zeiger auf einen konstanten String zurückgeben:

    const char *GetName() const{ return cName; }
    

    Übrigens ist der Konstruktor noch aus einem anderen Grunde fehlerhaft: SetName setzt ein initialisiertes cName voraus.

    1. Kann ich über das Vector-Array nicht auf meine vehicle Klasse bzw. Methoden zugreifen und verstehe auch hier den Compiler nicht wirklich.

    /SourceCode/Vector and Inheritance/main.cpp:50: error: 'class std::vector<vehicle, std::allocator<vehicle> >' has no member named 'ShowName'

    myVehiclePark ist ein Zeiger. Warum?
    Der eingebaute Indexoperator [] arbeitet mit Zeigern und Integern und wird hier benutzt.
    myVehiclePark[0] ist daher äquvalent zu *(myVeclePark+0) und das ERgebnis ist der Vektor selber, nicht ein Element des Vektors.

    Don06 schrieb:

    [Es musste ungefähr so aussehen:

    char* const GetName() const { return cName; }
    

    Gut gemeint aber verunglückt. const an dieser Stelle heißt eigentlich konstanter Zeiger auf nicht-konstantes char. Allerdings sind Ausdrücke mit Funktionsaufrufen stets rvalues, wenn der Rückgabetyp keine Referenz ist. rvalues von skalaren Typen sind aber niemals const/volatile-qualifiziert. Eine solche Qualifikation hätte bei Aufrufer keine Bedeutung, aus diesem Grund modifiziert der Compiler die Deklaration implizit so, dass das const an dieser Stelle verschwindet, die Signatur der so deklarierten Funktion ist tatsächlich:

    char* vehicle::GetName() const
    


  • Bedankt !!


Anmelden zum Antworten