为什么如果我们在基类中有纯虚拟赋值运算符,那么我们在派生类上实现该运算符,它会在基类上给出链接器错误?
目前我对http://support.microsoft.com/kb/130486只有以下解释,它说 行为是设计的,因为正常的继承规则不适用 。
我不清楚,为什么它会通过设计产生链接器错误?有人可以给我更明确的解释吗?
编辑:添加了发生错误的简化代码:
class __declspec(dllexport) BaseClass {
public:
int memberA;
virtual BaseClass& operator=(const BaseClass& rhs) = 0;
};
class __declspec(dllexport) DerivedClass : public BaseClass {
public:
int memberB;
DerivedClass():memberB(0) {}
virtual BaseClass& operator=(const BaseClass& rhs) {
this->memberA = rhs.memberA;
this->memberB = 1;
return *this;
}
};
int main(void)
{
DerivedClass d1;
DerivedClass d2;
BaseClass* bd1 = &d1;
BaseClass* bd2 = &d2;
*bd1 = *bd2;
}
代码将编译时没有错误没有 __declspec(dllexport)
和/或没有纯虚拟运算符=基类声明。
分配__declspec(dllexport)
后没有*bd1 = *bd2;
,d1 :: memberB为1,但__declspec(dllexport)
d1 :: memberB保持不变
__declspec(dllexport)
,没有纯虚拟声明,分配*bd1 = *bd2;
后,d1 :: memberB保持不变
答案 0 :(得分:7)
operator =不是继承的。您的代码在C ++中毫无意义,因此编译器可以随意发出任何错误。
从您指向的知识库文章:http://support.microsoft.com/kb/130486
由于不继承operator =,因此基类中的operator =的任何声明都是未使用且不必要的。不要在基类中声明operator =。
这可能只是他们如何编译的副作用,他们只是让你知道他们不认为它是一个bug,所以没有必要修复它。 “通过设计”并不一定意味着他们明确地决定这个链接器错误是正确的错误消息给出这种情况 - 代码是错误的,你得到一个错误,所以从他们的角度来看 - 他们是完成。
答案 1 :(得分:7)
从标准第12.8节开始:
13类X的隐式定义的复制赋值运算符执行其子对象的成员分配。 的 X的直接基类首先按照它们在base-specifier-list 中声明的顺序分配,然后立即分配 X的非静态数据成员按照在类定义中声明的顺序进行分配。每个子对象 以适合其类型的方式分配:
- 如果子对象是类类型,则使用该类的复制赋值运算符(就像通过显式限定; 也就是说,忽略更多派生类中任何可能的虚拟覆盖函数);
子类使用隐式定义的复制赋值运算符,并且没有基类的复制赋值运算符的定义,但它已声明,因此您会收到链接错误而不是编译错误。
答案 2 :(得分:2)
在示例代码中:
class A
{
public :
// To workaround LNK2001, comment the following line.
virtual const A& operator=( const A& f ) = 0;
};
class B : public A
{
public :
const A& operator=( const A& g ) {return g;}
};
B aB1, aB2;
int /*void*/ main( void )
{
aB2 = aB1;
}
行aB2 = aB1
不会调用const A& B::operator=(const A&)
,而是调用自动提供的B& operator=(const B&);
,后者又使用赋值运算符来指定类的基本部分。但是当谈到链接时,事实证明这种情况从未实现过。