2016-03-23 6 views
1

Gegeben ein Zeiger auf eine abstrakte Basisklasse A*, ich möchte es (als die Basisklasse) kopieren oder zuweisen und den abgeleiteten Kopierkonstruktor oder Zuweisungsoperator aufgerufen haben. Ich verstehe, dass Kopierkonstruktoren nicht virtuell sein können, daher ist der Kopierkonstruktor vermutlich keine Option dafür, sondern der Zuweisungsoperator. Trotzdem scheint es nicht zu funktionieren: der folgende Code drucktWie man abgeleiteten Zuweisungsoperator von der Basisklasse aufruft?

assigned a 
x! 
destroyed b 
destroyed b 

, die nicht zuweisen b.

#include <iostream> 
using namespace std; 

class A 
{ 
public: 
    virtual void x()=0; 
    virtual ~A() {} 
    virtual A& operator=(const A& other) { cout << "assigned a" << endl; return *this;} 
}; 

class B : public A 
{ 
public: 
    virtual B& operator=(const B& other) { cout << "assigned b" << endl; return *this;} 
    virtual void x() { cout << "x!" << endl; } 
    virtual ~B() { cout << "destroyed b" << endl; } 
}; 

int main() 
{ 
    A* a = new B(); 
    A* aa = new B(); 
    *aa=*a; 
    aa->x(); 
    delete a; 
    delete aa; 
    return 0; 
} 

Wie geht das?

EDIT Diese Frage wurde unten korrekt beantwortet, aber es war die falsche Frage. Ich sollte nicht versuchen, den Zuweisungsoperator zu überschreiben, weil ich nicht möchte, dass Unterklassen von A einander zuweisen. siehe die einfachere Antwort (hoffentlich) C++ elegantly clone derived class by calling base class

+0

Nicht dass es viel ausmacht, aber die Frage fragt nach einer ** virtuellen Basisklasse ** und der Code hat keine. –

+0

Ich denke du meinst * abstract * Basisklasse, nicht "virtual" (was eine ganz andere Sache ist). Die Abstraktheit der Basisklasse ist für Ihr Problem nicht relevant. – molbdnilo

+0

tue ich. Siehe Bearbeiten. –

Antwort

4

Das Problem ist, dass Ihre B::operator=nicht derjenige in A nicht außer Kraft setzen. Ändern Sie es in

virtual A& operator=(const A& other) { cout << "assigned b" << endl; return *this;} 

und es wird funktionieren. Versuchen Sie außerdem, das Schlüsselwort override beim Überschreiben von Elementfunktionen zu verwenden (erfordert C++ 11). Der Code wird nicht kompiliert, wenn Sie nicht überschreiben. In Ihrem Fall wäre es dein Fehler

error: 'virtual B& B::operator=(const B&)' marked 'override', but does not override

PS gefangen haben: Sie wahrscheinlich dachten über covariant return types. Damit es funktioniert, muss die Signatur Ihrer Funktion die gleiche sein wie der Rückgabetyp. ZB funktioniert das:

virtual B& operator=(const A& other) { cout << "assigned b" << endl; return *this;} 
+0

Ok, das ist gut, aber wie würde 'B :: operator =' auf Felder zugreifen, die für 'B' spezifisch sind, wenn es nicht garantieren kann, dass' const A & other' eine Instanz von 'B' ist? –

+0

@SideshowBob Sie können das Ergebnis eines ['dynamic_cast'] (http://en.cppreference.com/w/cpp/language/dynamic_cast) testen, um zu sehen, ob' other' wirklich ein 'B' ist. Aber das sollte dich auch denken lassen, ob dein Design solide ist. – vsoftco

+0

Die Tatsache, dass dies hart ist, lässt mich tatsächlich mein Design in Frage stellen. Letztendlich muss ich eine Klasse aus einem Basisklassenzeiger tief kopieren, ohne zu wissen, was die Klasse wirklich ist. Nach dem Prinzip der Verkapselung ist das keine verrückte Voraussetzung, oder? –