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

Use of assignment operator of derived class in base

本文关键字:赋值运算符 派生      更新时间:2023-10-16

我有一个类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

附言我知道这不是一个非常好的设计,但是我应该怎么做,如果假设我有一个指向 Base std::vector<Base*> v 对象的指针向量,并且它充满了派生类的对象(Derived1Derived2、一些其他类(,有时我必须将一个对象复制到另一个对象中。我不明白这样做的另一种解决方案是什么。

注意赋值运算符的参数不是Base的对象,而是对Base引用。这意味着您可以使用例如 dynamic_cast将其向下转换为对Derived1对象的引用。

您还可以使用奇怪的重复模板模式(或 CRTP(在 Base 类中使用参数和返回的正确类型来声明赋值运算符。

我不会将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
}