[英]How does the assignment operator overload resolution work in this example? The result is unexpected for me
Here is the code that I do not understand: 这是我不理解的代码:
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;
}
What are the language rules that determine, that the first assignment uses the operator of the Base class and the second the operator of the Derived class? 确定的第一个赋值使用Base类的运算符,第二个赋值使用Derived类的运算符的语言规则是什么?
Yes and I know that one normally does not declare an assignment operator like this. 是的,我知道通常不会像这样声明赋值运算符。 That is why I called it accademical.
这就是为什么我称它为accademical。
Short version : Overload resolution didn't select Base::operator=(Base)
. 短版本 :重载分辨率没有选择
Base::operator=(Base)
。 It selected the implicitly declared Derived::operator=(const Derived &)
, which calls Base::operator=(Base)
to copy-assign the base-class subobject. 它选择了隐式声明的
Derived::operator=(const Derived &)
,它调用Base::operator=(Base)
来复制 - 赋值基类子对象。
Long version with standard quotes: 带标准报价的长版 :
First, copy assignment operator is defined in the standard in §12.8 [class.copy]/p17: 首先,复制赋值运算符在§12.8[class.copy] / p17中的标准中定义:
A user-declared copy assignment operator
X::operator=
is a non-static non-template member function of class X with exactly one parameter of typeX
,X&
,const X&
,volatile X&
orconst volatile X&
.用户声明的复制赋值运算符
X::operator=
是类X的非静态非模板成员函数,其中只有一个参数类型为X
,X&
,const X&
,volatile X&
或const volatile X&
。
Second, if you don't provide a copy assignment operator, one will always be implicitly declared for you. 其次,如果您不提供复制赋值运算符,将始终为您隐式声明一个。 From §12.8 [class.copy]/p18:
来自§12.8[class.copy] / p18:
If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly.
如果类定义未显式声明复制赋值运算符,则会隐式声明一个。 If the class definition declares a move constructor or move assignment operator, the implicitly declared copy assignment operator is defined as deleted;
如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制赋值运算符被定义为已删除; otherwise, it is defined as defaulted (8.4).
否则,它被定义为默认值(8.4)。 The latter case is deprecated if the class has a user-declared copy constructor or a user-declared destructor.
如果类具有用户声明的复制构造函数或用户声明的析构函数,则不推荐使用后一种情况。 The implicitly-declared copy assignment operator for a class X will have the form
类X的隐式声明的复制赋值运算符将具有该表单
X& X::operator=(const X&)
if
如果
- each direct base class
B
ofX
has a copy assignment operator whose parameter is of typeconst B&
,const volatile B&
orB
, andX
每个直接基类B
都有一个复制赋值运算符,其参数类型为const B&
,const volatile B&
或B
,和- for all the non-static data members of
X
that are of a class type M (or array thereof), each such class type has a copy assignment operator whose parameter is of typeconst M&
,const volatile M&
orM
.对于类型为M(或其数组)的
X
所有非静态数据成员,每个这样的类类型都有一个复制赋值运算符,其参数类型为const M&
,const volatile M&
或M
Otherwise, the implicitly-declared copy assignment operator will have the form
否则,隐式声明的复制赋值运算符将具有该表单
X& X::operator=(X&)
Note that one of the results of these rules is that (§12.8 [class.copy]/p24): 请注意,这些规则的结果之一是(§12.8[class.copy] / p24):
Because a copy/move assignment operator is implicitly declared for a class if not declared by the user, a base class copy/move assignment operator is always hidden by the corresponding assignment operator of a derived class.
因为如果未由用户声明,则为类隐式声明复制/移动赋值运算符,则基类复制/移动赋值运算符始终由派生类的相应赋值运算符隐藏。
In other words, overload resolution can never select the copy assignment operator of Base
for an assignment from one Derived
to another. 换句话说,重载决策永远不能为从一个
Derived
到另一个Derived
的赋值选择Base
的复制赋值运算符。 It is always hidden and isn't even in the set of candidate functions. 它始终是隐藏的,甚至不在候选函数集中。
Finally, §12.8 [class.copy]/p28 provides that 最后,§12.8[class.copy] / p28提供了这一点
The implicitly-defined copy/move assignment operator for a non-union class X performs memberwise copy-/move assignment of its subobjects.
非联合类X的隐式定义的复制/移动赋值运算符执行其子对象的成员复制/移动分配。
In the case in the question, no copy assignment operator is provided for Derived
, so one will be implicitly declared as defaulted (since Derived
has no user-declared move constructor or move assignment operator). 在问题的情况下,没有为
Derived
提供复制赋值运算符,因此将隐式声明一个默认值(因为Derived
没有用户声明的移动构造函数或移动赋值运算符)。 This implicit copy assignment operator will be selected by overload resolution, and performs copy assignment of, among other things, the base class subobject, which calls the copy assignment operator you defined for Base
. 此隐式复制赋值运算符将通过重载决策选择,并执行基类子对象的复制赋值,该对象调用为
Base
定义的复制赋值运算符。
When you create a class, compiler implicitly generates following functions (unless you specify some of them explicitly see http://en.wikipedia.org/wiki/Special_member_functions ): 创建类时,编译器会隐式生成以下函数(除非您明确指定其中一些函数,请参阅http://en.wikipedia.org/wiki/Special_member_functions ):
In your case copy assignment operator signature is: 在您的情况下,复制赋值操作员签名是:
struct Foo {
Foo &operator=( const Foo &f ); // either this
Foo &operator=( Foo f ); // does not make much sense but will work too
};
When you create assignment operator for class Derived
, you do not explicitly replace implicit copy assignment operator but create a new one. 为
Derived
类创建赋值运算符时,不会显式替换隐式副本赋值运算符,而是创建一个新运算符。 To understand the issue easier modify your code to this: 要更轻松地了解此问题,请将代码修改为:
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;
}
};
Issue should become obvious. 问题应该变得明显。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.