在基中使用派生类的赋值运算符

时间:2019-02-01 12:52:23

标签: c++

我有一堂课Base

class Base{
    public:
    virtual ~Base();
    //I'm not sure about this, should it be virtual, or should it be "pure" virtual?
    virtual Base& operator=(const Base&);
}

如果Base类是由几个类派生的,例如

class Derived1: public Base{
    //...data 
    //standard assignment operator, it works for objects of class Derived1
    Derived1& operator=(const Derived&){
    //perform deep copy here
        std::cout<<"Derived1 assignment operator"<<std::endl;
    }
}

每个类都必须具有赋值运算符,因为这些类的某些数据成员是指针,因此我必须对它们进行深层复制。然后将以下代码不工作:

Base *d1 = new Derived1();
Base *d1_another = new Derived1();
//assignment operator is not called.
*d1 = *d1_another

如果我将基址的赋值运算符设为纯虚拟virtual Base& operator=(const Base&) = 0,则必须在每个子类中实现它。

class Derived1: public Base{
    //...data 
    //implementation of the base's assignment operator
    Base& operator=(const Base&){
    //how to access Derived1 fields? Casting?
    }
}

但是,如果传递给赋值运算符的对象是Base,该如何复制子类的成员?

PS我知道这不是一个很好的设计,但是,如果假设我有一个指向基数std::vector<Base*> v的对象的指针向量,并且其中充满了派生类的对象,那我应该怎么做? (Derived1Derived2,还有其他一些类),有时我不得不将一个对象复制到另一个对象中。我不明白什么是另一种解决方案。

2 个答案:

答案 0 :(得分:1)

请注意,赋值运算符的参数不是Base object ,而是对Base reference 。这意味着您可以使用dynamic_cast向下投射到对Derived1对象的引用。

您还可以使用the Curiously Recurring Template Pattern (or CRTP)Base类中声明赋值运算符,并使用正确的参数类型并返回。

答案 1 :(得分:0)

我不会用operator=做这种事情。如何处理将Derived2分配给Derived1

相反,我会有一个assign表示成功或失败,例如

class Base{
    protected:
    Base& operator=(const Base&) = default;
    Base& operator=(Base&&) = default;
    public:
    virtual ~Base() = default;
    virtual bool assign(const Base&) = 0;
    /* maybe ? virtual bool assign(Base&&) = 0; */
}

class Derived1: public Base{
    //...data 
    protected:
    Derived1& operator=(const Derived1 &) = default;
    public:
    bool assign(const Base & base){
        if (const Derived1 * derived = dynamic_cast<const Derived1 *>(&base))
        {
            *this = *derived;
            return true;
        }
        return false;
    }
}

int main() {
    Base *d1 = new Derived1();
    Base *d1_another = new Derived1();
    Base *d2 = new Derived2();

    //assignment operator is not called.
    assert(d1->assign(*d1_another)); // expect true, d1 is changed
    assert(!d2->assign(*d1_another)); // expect false, d2 is unchanged
}
相关问题