为什么我不能拥有一个纯粹的虚拟赋值运算符?

时间:2017-07-06 07:53:57

标签: c++ operator-overloading assignment-operator

我在C ++运营商中有点迷失。我想为两个不同的类强制执行赋值运算符,即可以将一个赋值给另一个:

class A {
public:
    virtual A &operator =(const A &a) = 0;
};

class B : public A {
public:
    virtual A &operator =(const A &a) override {
        std::cout << "B" << std::endl;
        return *this;
    }
};

class C : public A {
public:
    virtual A &operator =(const A &a) override {
        std::cout << "C" << std::endl;
        return *this;
    }
};

int main(int argc, char *argv[])
{
    B b;
    C c;
    b = c;

    // leads to a linker error: undefined reference to `A::operator=(A const&)'
    //B b2;
    //b = b2;
}

第一项任务似乎完成了工作,&#34; B&#34;叫做。同样,对于&#34; c = b&#34;,&#34; C&#34;叫做。但是,当我取消注释第二部分时,我收到链接器错误。如果我定义A的运算符,如:

virtual A &operator =(const A &a) {
        std::cout << "A" << std::endl;
        return *this;
} 

我得到&#34; B&#34;,&#34; A&#34;。咦?有人可以解释为什么&#34; A&#34;当分配两个B时需要,但是当B < - C是?

时不需要

3 个答案:

答案 0 :(得分:2)

编译器生成一个隐式复制赋值运算符,当您执行B = B赋值时,该运算符被选中。执行B = C分配时,不会选择此选项。

http://en.cppreference.com/w/cpp/language/copy_assignment

https://wandbox.org/permlink/CM5tQU656rnwtrKl

如果您查看错误消息:

/tmp/cctHhd0D.o: In function `B::operator=(B const&)':
prog.cc:(.text._ZN1BaSERKS_[_ZN1BaSERKS_]+0x1f): undefined reference to `A::operator=(A const&)'
collect2: error: ld returned 1 exit status

您可以看到链接器错误来自B::operator=(B const&)内部,因为您没有定义它,意味着它必须是自动生成的。

答案 1 :(得分:2)

当您指定b = b2;时,它会尝试调用B的默认(隐式)赋值。 默认赋值将调用基类的默认赋值,因此它最终将调用A::operator=(const A &a),这是纯虚拟的。

所以你得到链接错误。

答案 2 :(得分:1)

根据标准覆盖派生类中基类的虚拟赋值运算符,不会阻止生成在您的情况下调用的默认复制赋值运算符。类B的此默认复制赋值运算符将直接调用类A的复制赋值运算符,因此会出现undefined reference错误。

  

13.5.3作业[over.ass]

     

2任何赋值运算符,甚至是复制和移动赋值运算符,都可以是虚拟的。 [注意:对于已声明虚拟副本/移动分配的基类B的派生类D,D中的复制/移动赋值运算符不会覆盖B的虚拟副本/移动赋值运算符。 [实施例:

struct B {
    virtual int operator= (int);
    virtual B& operator= (const B&);
};

struct D : B {
    virtual int operator= (int);
    virtual D& operator= (const B&);
};

D dobj1;
D dobj2;
B* bptr = &dobj1;

void f()
{
    bptr->operator=(99); // calls D::operator=(int)
    *bptr = 99; // ditto
    bptr->operator=(dobj2); // calls D::operator=(const B&)
    *bptr = dobj2; // ditto
    dobj1 = dobj2; // calls implicitly-declared D::operator=(const D&)
}