![](/img/trans.png)
[英]How does operator overload resolution work in the presence of the new initializer sequence?
[英]How does the assignment operator overload resolution work in this example? The result is unexpected for me
这是我不理解的代码:
class Base
{
public:
Base(){}
Base operator=(Base ob2)
{
std::cout << "Using Base operator=() " << '\n';
return *this;
}
};
class Derived : public Base
{
public:
Derived(){}
Derived operator=(Base ob2)
{
std::cout << "Using Derived operator=() " << '\n';
return *this;
}
};
int main()
{
Derived derived1, derived2;
Base base1;
derived1 = derived2; // Uses base operator=()
derived1 = base1; // Uses derived operator=()
return 0;
}
确定的第一个赋值使用Base类的运算符,第二个赋值使用Derived类的运算符的语言规则是什么?
是的,我知道通常不会像这样声明赋值运算符。 这就是为什么我称它为accademical。
短版本 :重载分辨率没有选择Base::operator=(Base)
。 它选择了隐式声明的Derived::operator=(const Derived &)
,它调用Base::operator=(Base)
来复制 - 赋值基类子对象。
带标准报价的长版 :
首先,复制赋值运算符在§12.8[class.copy] / p17中的标准中定义:
用户声明的复制赋值运算符
X::operator=
是类X的非静态非模板成员函数,其中只有一个参数类型为X
,X&
,const X&
,volatile X&
或const volatile X&
。
其次,如果您不提供复制赋值运算符,将始终为您隐式声明一个。 来自§12.8[class.copy] / p18:
如果类定义未显式声明复制赋值运算符,则会隐式声明一个。 如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制赋值运算符被定义为已删除; 否则,它被定义为默认值(8.4)。 如果类具有用户声明的复制构造函数或用户声明的析构函数,则不推荐使用后一种情况。 类X的隐式声明的复制赋值运算符将具有该表单
X& X::operator=(const X&)
如果
X
每个直接基类B
都有一个复制赋值运算符,其参数类型为const B&
,const volatile B&
或B
,和- 对于类型为M(或其数组)的
X
所有非静态数据成员,每个这样的类类型都有一个复制赋值运算符,其参数类型为const M&
,const volatile M&
或M
否则,隐式声明的复制赋值运算符将具有该表单
X& X::operator=(X&)
请注意,这些规则的结果之一是(§12.8[class.copy] / p24):
因为如果未由用户声明,则为类隐式声明复制/移动赋值运算符,则基类复制/移动赋值运算符始终由派生类的相应赋值运算符隐藏。
换句话说,重载决策永远不能为从一个Derived
到另一个Derived
的赋值选择Base
的复制赋值运算符。 它始终是隐藏的,甚至不在候选函数集中。
最后,§12.8[class.copy] / p28提供了这一点
非联合类X的隐式定义的复制/移动赋值运算符执行其子对象的成员复制/移动分配。
在问题的情况下,没有为Derived
提供复制赋值运算符,因此将隐式声明一个默认值(因为Derived
没有用户声明的移动构造函数或移动赋值运算符)。 此隐式复制赋值运算符将通过重载决策选择,并执行基类子对象的复制赋值,该对象调用为Base
定义的复制赋值运算符。
创建类时,编译器会隐式生成以下函数(除非您明确指定其中一些函数,请参阅http://en.wikipedia.org/wiki/Special_member_functions ):
在您的情况下,复制赋值操作员签名是:
struct Foo {
Foo &operator=( const Foo &f ); // either this
Foo &operator=( Foo f ); // does not make much sense but will work too
};
为Derived
类创建赋值运算符时,不会显式替换隐式副本赋值运算符,而是创建一个新运算符。 要更轻松地了解此问题,请将代码修改为:
class Derived : public Base
{
public:
Derived(){}
Derived &operator=(const Base &ob2)
{
std::cout << "Using Derived operator=(Base) " << '\n';
return *this;
}
Derived &operator=(const Derived &ob2)
{
std::cout << "Using Derived operator=(Derived) " << '\n';
return *this;
}
};
问题应该变得明显。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.