Vererbung, Methoden überschreiben



  • Hallo,

    ich hab eine kurze Frage zur Vererbung in C++.
    Ich bräuchte eine Basisklasse, die wie ein "Interface" funktionieren sollte.
    D.h. ich würde davon dann verschiedene andere Klassen ableiten,
    die die Funktionen der Basisklasse implementieren (bzw. überschreiben) sollten.
    Mein Problem ist aber, dass ich danach einen Vektor solchen Objekten abspeichern möchte. D.h. der Vektor hat den Typ der Basisklasse. Die Objekte drin sind aber ausschließlich Objekte der abgeleiteten Klassentypen.
    Mein Ziel wäre es aber, wenn ich dann eine Methode auf einem dieser Objekte im Vektor aufrufe, dass dann die Methode der abgeleiteten Klasse ausgeführt wird.

    Konkret hab ich momentan eine Basisklasse:

    class Basis {
    public:
    	virtual ~Basis();
    	virtual double getSomething();
    };
    

    mit Implementierung:

    Basis::~Basis() {}
    double Basis::getSomething() {
    	return -1;
    }
    

    Und abgeleitete Klassen:

    class SomeImplementation: public Basis {
    public:
    	SomeImplementation();
    	virtual ~SomeImplementation();
    	virtual double getSomething();
    };
    

    mit Implementierung:

    SomeImplementation::SomeImplementation() {}
    SomeImplementation::~SomeImplementation() {}
    double SomeImplementation::getSomething() {
    	return +1;
    }
    

    Ich habe einen Vektor, der verschiedene Typen gruppiert und speichert:

    vector<Basis> differentObjects;
    

    Ich initialisiere verschiedene Objekte der spezifischen Klassen und füge diese zum Vektor dazu:

    SomeImplementation obj = SomeImplementation();
    differentObjects.push_back(obj);
    

    Wenn ich jetzt aber eine Methode auf diesen Objekten im Vektor aufrufe, wird automatisch die Methode der Basisklasse ausgeführt. D.h. beim Aufruf von doSomething() auf diesen Objekten ist mein Rückgabewert -1 , nicht +1 .

    Kann ich das irgendwie umgehen?
    Bzw. wie mache ich das richtig?

    Vielen Dank schon mal für die Hilfe 🙂 ,
    viele Grüße



  • Kommst du aus der JAVA Ecke? Sieht so aus. Du hast die Objekte in Reinform reinkopiert und dann wird der Copy Constructor vom Basetyp aufgerufen. Du brauchst Pointer. Am Besten fängst du direkt mit smart pointers an. Wenn du C++0x support hast unique_ptr sonst shared_ptr. Google das, setz es ein, Problem gelöst.

    mfg, René~



  • Genau 😉
    Aber mit Pointern geht's jetzt 🙂
    DANKE 🙂



  • Wenn du Boost hast, nimm boost::ptr_vector . Von der Schnittstelle fast gleich wie std::vector , aber auf Zeiger (z.B. bei Polymorphie) spezialisiert und selbstaufräumend. Mit Smart-Pointers hast du unter Umständen einen Overhead, den du nicht brauchst (sollte das überhaupt je relevant sein) und eine weniger schöne Syntax.

    Übrigens, std::unique_ptr ist nicht kopierbar, nur verschiebbar.



  • Nexus schrieb:

    Übrigens, std::unique_ptr ist nicht kopierbar, nur verschiebbar.

    std::vector + unique_ptr > ptr_vector

    Zumindestens meiner Meinung nach. Und dass sie nicht kopierbar sind ist ja gerade das schöne und eindeutige an der Sache. Man braucht nur sehr selten kopierbare Pointer. Die ganzen STL Container sind übrigens mit C++0x move kompatibel und damit unique_ptr kompatibel.



  • Ich kenne mich mit std::unique_ptr noch zu wenig aus, um die Angelegenheit gut beurteilen zu können.

    Aber inwiefern sind STL-Container move-kompatibel? Sehr viele Operationen und Algorithmen verlassen sich auf Kopien. Was wird dann dort gemacht?



  • Nexus schrieb:

    Aber inwiefern sind STL-Container move-kompatibel? Sehr viele Operationen und Algorithmen verlassen sich auf Kopien. Was wird dann dort gemacht?

    Tja, da wird sich dann halt nicht mehr auf Kopien verlassen. Teilweise sind gewisse Methoden kompatibel und teilweise gibt es neue Methoden im Standard (z.B. emplace), die dann dafür genutzt werden können. Vielleicht sind sogar alle alten Methoden kompatibel und es liegt nur am aktuellen GCC Stand, das habe ich aber nicht nachgeforscht, ich benutze einfach das was geht (maps sind leider noch nicht nutzbar im GCC).

    Bei vectors besteht z.B. kaum ein Unterschied, push funktioniert, erase funktioniert, random access funktioniert. Beispiel für das hinzufügen eines Pointers:

    void User::addRealEstate(unique_ptr<RealEstate> &&realEstate) throw()
    {
    	realEstates_.push_front(move(realEstate));
    }
    

    mfg, René~



  • Aber zum Beispiel Funktionen wie std::fill() . Oder subtiler wie std::sort() , das prinzipiell Kopien erstellen darf. Und natürlich viele eigene Algorithmen. Oder auch Kopien von ganzen Containern. Das geht dann halt nicht ohne Weiteres. Man ist wohl schon um einiges eingeschränkter nur mit Move-Semantik. Aber darin besteht ja auch ein Vorteil des Ganzen.



  • Wenn du nur eine Art "Interface" haben willst, kannst du die Funktionen der Basisklasse auch abstrakt machen und musst sie nicht implementieren:

    virtual double getSomething() = 0;
    

Log in to reply