1

Ich schreibe gerade eine komplizierte Klasse und darin muss ich im Grunde eine Liste abgeleiteter Klassen kopieren. Die vereinfachte Version ist wie folgt: ich eine Basisklasse, von denen ich einige andere Klassen ableiten:C++ Zuweisungsoperator = Überladen mit abgeleiteten Klassen

class Base 
{ 
public: 
    virtual void test(void) 
    { 
     cout << "Base" << endl; 
    } 
    Base(vector<Base*> *pointer) 
    { 
     pointer->push_back(this); 
    } 
    virtual Base& operator=(const Base& rhs) 
    { 
     cout << "Base=" << endl; 
     return *this; 
    } 
}; 
class A : public Base 
{ 
public: 
    void test(void) 
    { 
     cout << "A" << endl; 
    } 
    A(vector<Base*> *pointer) : Base(pointer) {} 
    A& operator=(const A& rhs) 
    { 
     cout << "A=" << endl; 
     return *this; 
    } 
}; 
class B : public Base 
{ 
public: 
    void test(void) 
    { 
     cout << "B" << endl; 
    } 
    B(vector<Base*> *pointer) : Base(pointer) {} 
    B& operator=(const B& rhs) 
    { 
     cout << "B=" << endl; 
     return *this; 
    } 
}; 

Dann erstelle ich eine Liste von Objekten, die ich in der in einer Zeigerliste der Basisklasse speichern :

Diese Objekte sind mit den gleichen Klassen (gleiche Reihenfolge) I, in einer zweiten Liste will dann kopieren, aber die unterschiedlichen Werte haben könnte.

for (int i = 0; i < (int)listA.size(); i++) 
{ 
    (*listA[i]) = (*listB[i]); 
} 

Aber C++ ist nicht in der Lage, das zu tun. Da die Liste den Typ Base * hat, erstellt Dereferenzierung ein Objekt vom Typ Base. Daher wird der Zuweisungsoperator = der Base-Klasse anstelle der korrekten der abgeleiteten Klasse aufgerufen. Wie kann ich das beheben?

Oder wie kann ich C++ sagen, den richtigen Operator zu verwenden? Vielleicht von einigen isinstanceof-Funktion?

Für eine vollständige Probe siehe:

int main() 
{ 
    vector<Base*> listA; 

    new Base(&listA); 
    new A(&listA); 
    new B(&listA); 

    vector<Base*> listB; 

    new Base(&listB); 
    new A(&listB); 
    new B(&listB); 


    for (int i = 0; i < (int)listA.size(); i++) 
    { 
     (*listA[i]).test(); 
    } 
    for (int i = 0; i < (int)listA.size(); i++) 
    { 
     (*listA[i]) = (*listB[i]); 
    } 
} 

Welche Ausgänge:

Base 
A 
B 
Base= 
Base= 
Base= 
+0

Mögliches Duplikat von [Warum verwendet eine abgeleitete Klasse nicht den Basisklassenoperator = (Zuweisungsoperator)?] (Http://stackoverflow.com/questions/10838211/why-doesnt-a-derived-class-use) -the-base-class-Operator-Zuweisungsoperator? rq = 1) –

+0

Was bedeutet es, ein "A" einem "B" zuzuweisen oder umgekehrt? – aschepler

Antwort

0

Okay. Ich habe eine Lösung für mein Problem gefunden. Ich habe eine Kopierfunktion implementiert, die die Base-Klasse als Argument verwendet. Innerhalb dieser Kopierfunktion kann ich die Variablen mit dem pointa kopieren. Die classe sind nun wie folgt:

class Base 
{ 
public: 
    virtual void test(void) 
    { 
     cout << "Base" << endl; 
    } 
    Base(vector<Base*> *pointer) 
    { 
     pointer->push_back(this); 
    } 
    virtual void clone(Base* pointer) = 0; 
}; 
class A : public Base 
{ 
public: 
    void test(void) 
    { 
     cout << "A" << endl; 
    } 
    A(vector<Base*> *pointer) : Base(pointer) {} 
    void clone(Base* pointer) override 
    { 
     A* pointa = (A*)pointer; 
     cout << "clone A" << endl; 
     //Clone Variables here 
    } 
}; 
class B : public Base 
{ 
public: 
    void test(void) 
    { 
     cout << "B" << endl; 
    } 
    B(vector<Base*> *pointer) : Base(pointer) {} 
    void clone(Base* pointer) override 
    { 
     B* pointa = (B*)pointer; 
     cout << "clone B" << endl; 
     //Clone Variables here 
    } 
}; 

Dies bedeutet, dass ich jetzt die Objekte auf folgende Weise kopieren:

for (int i = 0; i < (int)listA.size(); i++) 
{ 
    listA[i]->clone(listB[i]); 
} 

Doch diese Lösung ist nicht in irgendeiner Weise typsicher, eine Anforderung ich treffen möchte . Ich habe meine Idee untersucht und entschieden, die Dinge ohne die Liste manuell zu machen, was viel doppelten Code bedeutet, aber Ruhe bringt.

2

Es gibt einige Missverständnisse hier. In erster Linie: Was bedeutet es, einer Instanz einer Basisklasse eine Instanz einer abgeleiteten Klasse zuzuweisen? Lassen Sie uns eine einfache Hierarchie nehmen:

struct A { int x; }; 
struct B : A { int y; }; 

A a; 
B b; 
a = b; // what should this do? 
b = a; // what about this? 

Bei normalen C++, hat die erste object slicing, und die zweite ist schlecht ausgebildet. Aber selbst der erste, wohlgeformte, ist in der Regel nicht das, was du sowieso machen willst. Sind Sie sicher möchten Sie schneiden?


Die zweite ist, dass, während Sie Ihre Zuweisungsoperator virtuelle gemacht:

virtual Base& operator=(const Base& rhs) 

Keiner der abgeleiteten Klassen es

tatsächlich außer Kraft setzen. A 's Zuweisungsoperator nimmt eine A const& und B' s nimmt eine B const&. Wenn Sie die beiden mit override markiert haben, würde Ihr Compiler Sie darauf hinweisen. Wenn Sie diese beiden beheben, um ein Base const& Argument zu nehmen, dann würden Sie bekommen, was Sie gedruckt haben wollen - aber es ist wahrscheinlich immer noch nicht das, was Sie eigentlich haben wollen.


Um tatsächlich polymorphe Kopien zu machen, eine typische Lösung ist eine virtuelle Klon-Methode zur Verfügung zu stellen:

virtual Base* clone() const = 0; 

Dass Ihre abgeleiteten Klassen implementieren:

struct A : Base { 
    A* clone() const override { return new A(*this); } 
}; 

Und dann verwenden clone() anstelle der Zuordnung. Hier wird nicht geschnitten.


Fügen Sie hier die üblichen Vorbehalte über Speicherverwaltung und rohe Zeiger ein.

+0

Danke! Ich verstehe was du sagst. Nur den letzten Teil kann ich nicht umschließen. Wie würde ich diese Klonfunktion in der Praxis verwenden? – jansende

+0

Sie meinen, indem Sie das alte Objekt vollständig ersetzen? Leider ist das keine Option! – jansende