1

В настоящее время я пишу сложный класс, и в нем мне в основном нужно скопировать список производных классов. Упрощенная версия следующим образом: У меня есть базовый класс, от которого я вывожу несколько других классов:Оператор присваивания C++ = перегрузка с производными классами

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; 
    } 
}; 

Затем создать список объектов, которые я сохранить в в списке указателя класса Base :

vector<Base*> listA; 

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

Эти объекты затем я хочу, чтобы скопировать во второй список с теми же классами (тот же порядок), но которые могут иметь разные значения.

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

Однако C++ не может этого сделать. Поскольку список имеет тип Base *, разыменование создает объект типа Base. Поэтому оператор присваивания = базового класса вызывается вместо правильного из производного класса. Как я могу это исправить?

Или как я могу сказать C++ использовать правильный оператор? Может быть, какая-то функция?

Для полного образца SEE:

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]); 
    } 
} 

Какие выходы:

Base 
A 
B 
Base= 
Base= 
Base= 
+0

Возможный дубликат [Почему не производный класс использует оператор базового класса = (оператор присваивания)?] (Http://stackoverflow.com/questions/10838211/why-doesnt-a-derived-class-use оператор базового класса-оператора-присваивания? rq = 1) –

+0

Что значит назначать 'A'' B' или наоборот? – aschepler

ответ

0

Хорошо. Я нашел решение для своей проблемы. Я реализовал функцию копирования, которая берет класс Base в качестве аргумента. Внутри этой функции копирования я могу скопировать переменные, используя pointa. Classe теперь следующим образом:

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 
    } 
}; 

Это означает, что теперь я могу скопировать объекты следующим образом:

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

Однако это решение не является каким-либо образом типизированного, требование я хочу , Я задумался над своей идеей и решил сделать все вручную без списка, что означает много дублированного кода, но приносит душевное спокойствие.

2

Есть несколько недоразумений здесь. Прежде всего, что означает присвоение экземпляра производного класса экземпляру базового класса? Давайте возьмем простую иерархию:

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

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

При нормальном C++, первый делает object slicing, а второй один плохо сформирован. Но даже первый, хорошо сформированный, обычно не то, что вы хотите сделать в любом случае. Вы уверены хотите ли вы нарезать?


Во-вторых, в то время как вы сделали свой оператор присваивания виртуальным:

virtual Base& operator=(const Base& rhs) 

Ни один из производных классов на самом деле не заменить его. A занимает A const& и B занимает B const&. Если вы отметили два с override, ваш компилятор укажет вам это. Если вы исправите эти два, чтобы принять аргумент Base const&, тогда вы получите то, что хотите напечатать, но это, вероятно, все еще не то, что вы действительно хотите.


Для того, чтобы действительно сделать полиморфные копии, типичное решение заключается в создании способа виртуального клона:

virtual Base* clone() const = 0; 

Это ваши производные классы реализации:

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

И затем использовать clone() вместо назначения. Здесь не будет нарезки.


Вставьте здесь обычные оговорки об управлении памятью и необработанных указателях.

+0

Спасибо! Я понимаю, что вы говорите. Только последняя часть, на которую я не могу окутать голову. Как бы я использовал эту функцию клонирования на практике? – jansende

+0

Вы имеете в виду, полностью заменив старый объект? К сожалению, это не вариант! – jansende

Смежные вопросы