我很困惑......为什么我的任务操作员不会在这里被调用?
template<typename This>
struct mybase
{
This& operator =(const This &other)
{
__debugbreak(); // The debugger should break here, but doesn't.
return static_cast<This &>(*this):
}
};
struct myderived : mybase<myderived>
{
int x;
};
int main()
{
myderived a = myderived(); // And yes, I know it's redundant...
myderived b = myderived();
a = b;
return 0;
}
答案 0 :(得分:6)
因为derived中的默认赋值运算符将隐藏重载的基数。
答案 1 :(得分:5)
mybase::operator=
myderived::operator=
隐藏。
您可以使用using
声明使派生类中的基类运算符可见。
编辑:为每个请求添加了示例:
template<typename This>
struct mybase
{
This& operator =(const This &other)
{
//__debugbreak(); // The debugger should break here, but doesn't.
return static_cast<This &>(*this);
}
};
struct myderived : mybase<myderived>
{
using mybase<myderived>::operator=;
int x;
};
int main()
{
myderived a = myderived(); // And yes, I know it's redundant...
myderived b = myderived();
a = b;
}
使用Visual C ++ 10.0和Comeau Online可以很好地编译。实际上,后者意味着它是很好的标准C ++。但是,代码不能使用MinGW g ++ 4.4.1(编译器错误)进行编译。
编辑2:实际上,现在检查,使用Visual C ++ 10.0进行编译,但不调用基类操作符。所以也许g ++是正确的。 using
通常是引入基类赋值运算符(或其他)的方法,但在这种情况下它与派生类'复制赋值运算符具有相同的签名,我还不知道Visual C ++是否有行为是否正确 - 这是该语言的一个极端情况。
编辑3:我检查了N3290(与C ++ 11完全相同的标准草案),它说
<强>§12.8/ 18:强>
如果类定义未显式声明复制赋值运算符,则会隐式声明一个。如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制赋值运算符被定义为已删除;否则,它被定义为默认值(8.4)。
我个人解释说,在using
声明的情况下,类“声明”了一个复制赋值运算符,因此不应该隐式生成(因为它似乎是Visual C ++ 10.0所做的)。但是,这是该语言的一个极端情况。其他人可能会对此有不同的解释,如上所述,编译器也有所不同!
干杯&amp;第h。,
答案 2 :(得分:3)
这一行:
a = b;
显然要求myderived
重载了复制赋值运算符。它可以由编译器隐式生成,也可以由myderived
类明确定义:
12.8复制类对象[class.copy]
9. 用户声明的复制赋值运算符
X::operator=
是a 类X
的非静态非模板成员函数,只有一个 类型X
,X&
,const X&
,volatile X&
或const volatile X&
的参数。
您已尝试在mybase
类中创建用户声明的复制赋值运算符,但根据C ++标准,它实际上并不是复制赋值运算符。想象一下,如果我们使用This
对myderived
进行了类型替换:
// Hypothetical class generated by the compiler from
// the mybase template class with This = myderived
struct mybase_myderived
{
myderived& operator =(const myderived &other)
{
// ...
}
};
显然,这不是复制赋值运算符,因为参数other
的类型为const myderived&
,而不是const mybase&
。如果other
参数属于const mybase&
类型,或mybase
或mybase&
,那么它将是一个有效的复制赋值运算符,可以通过默认的复制赋值调用myderived
中的运算符。但它不是在这种情况下,所以编译器仍然为mybase
生成一个默认的复制赋值运算符,在这种情况下当然不会做任何事情。
myderived
中编译器生成的默认复制赋值运算符在mybase
中调用编译器生成的默认复制赋值运算符。所以最终会发生什么,因此,永远不会调用operator=(const myderived &other)
重载。
编译器不直接调用mybase::operator=
的原因是因为它被myderived
中编译器生成的复制赋值运算符隐藏了,正如Alf P. Steinbach在{{3}中指出的那样。 }}
答案 3 :(得分:2)
因为编译器在myderived中引入了默认赋值运算符。覆盖它并自己调用您的基本赋值运算符。或者也许使用指令会有所帮助?尝试在myderived body中使用mybase :: operator =。