2017-07-06 75 views
3

我有点迷失在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; 
} 

的第一项任务,似乎做的工作,“B”之称。类似地,对于“c = b”,调用“C”。但是,当我取消注释第二部分时,我收到链接器错误。如果我将A的运营商定义为:

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

我得到“B”,“A”。咦?有人可以解释为什么当分配两个B时需要“A”,但是当B不是时B?

+0

你认识到,编译器也为B和C的一个默认的拷贝构造函数,以及默认NON VIRTUAL B ::运算符=(常数B&)和C ::运算(常量C&)操作符....创建虚拟(甚至非虚拟)赋值操作符从基到派生是要求麻烦的。 –

+0

这不是问题,但是你真的需要'std :: endl'做的额外的东西吗? ''\ n''结束一行。 –

回答

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&),其中,因为你没有一个定义,意味着它必须是自动生成的。

+0

因此,没有任何直接的方法来迫使程序员为给定类型提供赋值运算符?我猜连接器错误可能被称为强制执行,但我宁愿一个编译器错误。 –

+0

@MiroKropacek据我所知,没有。复制分配操作符是特殊的。另外,请仔细考虑从基类到派生类是否有意义.. – xaxxon

+0

tbh,我也不觉得很舒服。它只是看起来更小的邪恶。对B中的'C'和C中的'B'进行单独的运算符看起来更加陌生,更不用说强制执行了,把A作为纯粹的虚拟方法看起来并不正确。 –

2

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

所以你得到的链接错误。

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&) 
} 
相关问题