简体   繁体   English

c ++赋值运算符=使用派生类重载

[英]c++ assignment operator= overloading with derived classes

I'm currently writing a complicated class and in it I basically need to copy a list of derived classes. 我正在编写一个复杂的类,在其中我基本上需要复制派生类的列表。 The simplified version is, as follows: I have a base class from which I derive several other classes: 简化版本如下:我有一个基类,我可以从中派生出其他几个类:

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

Then I create a list of objects, which I save in the in a pointer list of the Base class: 然后我创建一个对象列表,我将其保存在Base类的指针列表中:

vector<Base*> listA;

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

These objects I then want to copy in a second list with the same classes (same order), but which might have different values. 然后,我想要在具有相同类(相同顺序)的第二个列表中复制这些对象,但这些对象可能具有不同的值。

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

However c++ is not able to do that. 但是c ++无法做到这一点。 Because the list has the type Base*, dereferencing creates an object of type Base. 由于列表的类型为Base *,因此解除引用会创建Base类型的对象。 Therefore the assignment operator= of the Base class is called instead of the correct one from the derived class. 因此,从派生类调用Base类的赋值运算符=而不是正确的赋值运算符。 How can I fix this? 我怎样才能解决这个问题?

Or how can I tell c++ to use the right operator? 或者我如何告诉c ++使用正确的运算符? Maybe by some isinstanceof-function? 也许是某种功能?

For a full sample 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]);
    }
}

Which outputs: 哪个输出:

Base
A
B
Base=
Base=
Base=

There are a few misunderstandings here. 这里有一些误解。 First and foremost, what does it mean to assign an instance of a derived class to an instance of a base class? 首先,将派生类的实例分配给基类的实例意味着什么? Let's take a simple hierarchy: 我们采取一个简单的层次结构:

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

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

With normal C++, the first one does object slicing , and the second one is ill-formed. 使用普通的C ++,第一个进行对象切片 ,第二个进行异常切换 But even the first one, well well-formed, is typically not what you want to do anyway. 但即便是第一个,形状良好,通常也不是你想要做的。 Are you sure you want to be slicing? 确定要切片吗?


The second is that while you made your assignment operator virtual: 第二个是,当您将赋值运算符设为虚拟时:

virtual Base& operator=(const Base& rhs)

None of the derived classes actually override it. 没有派生类实际覆盖它。 A 's assignment operator takes an A const& and B 's takes a B const& . A 's赋值运算符取一个A const&B '取一个B const& If you marked the two with override , your compiler would point this out to you. 如果您使用override标记了两个,则编译器会将此指向您。 If you fix those two to take a Base const& argument, then you would get what you want printed - but it's probably still not what you actually want to have happen. 如果你修复这两个以获取一个Base const&参数,那么你会得到你想要的东西 - 但它可能仍然不是你真正想要发生的。


In order to actually make polymorphic copies, a typical solution is to provide a virtual clone method: 为了实际制作多态副本,典型的解决方案是提供虚拟克隆方法:

virtual Base* clone() const = 0;

That your derived classes implement: 您的派生类实现:

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

And then use clone() instead of assignment. 然后使用clone()而不是赋值。 There will be no slicing here. 这里没有切片。


Insert the usual caveats about memory management and raw pointers here. 在此处插入有关内存管理和原始指针的常见警告。

Okay. 好的。 I found a solution for my problem. 我找到了解决问题的方法。 I implemented a copy function which takes the Base class as the argument. 我实现了一个以Base类为参数的复制函数。 Inside this copy function I can copy the variables using the pointa . 在这个复制函数中,我可以使用pointa复制变量。 The classe now are as follows: 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
    }
};

This means I can now copy the objects in the following way: 这意味着我现在可以通过以下方式复制对象:

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

However this solution is not in any way typesafe, a requirement I want to meet. 然而,这个解决方案绝不是类型安全的,这是我想要满足的要求。 I looked into my idea, and decided to do things manually without the list, which means lot's of duplicated code, but brings peace of mind. 我调查了我的想法,并决定在没有列表的情况下手动执行操作,这意味着很多重复的代码,但带来了安心。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM