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类的指针列表的列表:

这些对象,然后我想在同一个班(顺序相同)第二列表复制,但它可能有不同的值。

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

但是C++无法做到这一点。由于列表的类型是Base *,因此dereferencing会创建一个Base类型的对象。因此调用基类的赋值运算符=而不是从派生类中正确的。我怎样才能解决这个问题?

或者我该如何告诉C++使用正确的运算符?也许由一些isinstanceof功能?

对于全样本见:

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 -base-class-operator-assignment-operator?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