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

时间:2016-07-31 16:11:03

标签: c++ list operator-overloading derived-class assignment-operator

我正在编写一个复杂的类,在其中我基本上需要复制派生类的列表。简化版如下: 我有一个基类,我可以从中派生出其他几个类:

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类型的对象。因此,从派生类调用Base类的赋值运算符=而不是正确的赋值运算符。我该如何解决这个问题?

或者如何告诉c ++使用正确的运算符?也许是某种功能的实例?

如需完整样本,请参阅:

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=

2 个答案:

答案 0 :(得分:3)

这里有一些误解。首先,将派生类的实例分配给基类的实例意味着什么?我们采用一个简单的层次结构:

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的{​​{1}}需要B const&。如果您使用override标记了两个,则编译器会将此指向您。如果你修复这两个以获得Base const&参数,那么你会得到你想要的东西 - 但它可能仍然不是你真正希望发生的。

为了实际制作多态副本,典型的解决方案是提供虚拟克隆方法:

virtual Base* clone() const = 0;

您的派生类实现:

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

然后使用clone()代替分配。这里没有切片。

在此处插入有关内存管理和原始指针的常见警告。

答案 1 :(得分:0)

好。我找到了解决问题的方法。我实现了一个以Base类为参数的复制函数。在这个复制功能中,我可以使用select "column", "encoding" from pg_table_def where tablename = 'foo'; column | encoding --------+---------- id | lzo name | lzo (2 rows) 复制变量。 classe现在如下:

pointa

这意味着我现在可以通过以下方式复制对象:

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

然而,这个解决方案绝不是类型安全的,这是我想要满足的要求。我查看了我的想法,并决定在没有列表的情况下手动执行操作,这意味着很多重复的代码,但带来了安心。