简体   繁体   English

在此示例中,赋值运算符重载解析如何工作? 结果对我来说意外

[英]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 type X , X& , const X& , volatile X& or const volatile X& . 用户声明的复制赋值运算符X::operator=是类X的非静态非模板成员函数,其中只有一个参数类型为XX&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 of X has a copy assignment operator whose parameter is of type const B& , const volatile B& or B , and X每个直接基类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 type const M& , const volatile M& or M . 对于类型为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 ):

  • default constructor 默认构造函数
  • copy constructor 复制构造函数
  • move constructor (since c++11) 移动构造函数(从c ++ 11开始)
  • copy assignment operator 复制赋值运算符
  • move assignment operator (since c++11) 移动赋值运算符(自c ++ 11起)
  • destructor 析构函数

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.

相关问题 在新的初始化序列存在的情况下,运算符重载解析如何工作? - How does operator overload resolution work in the presence of the new initializer sequence? 运算符如何在名称空间中重载解析? - How does the operator overload resolution work within namespaces? std :: string如何使赋值运算符重载? - How does std::string overload the assignment operator? 重载解析如何与可变参数函数一起使用? - How does overload resolution work with variadic functions? 如何在以下c ++代码中基于返回类型进行运算符重载解析 - how does operator overload resolution work based on return type in the following code of c++ 运算符重载解析在名称空间内工作 - Operator overload resolution work within namespaces 插入运算符 (operator&lt;&lt;) 的这种递归重载是如何工作的? - How does this recursive overload of the insertion operator (operator<<) work? 我可以重载一个重载的运算符吗? 操作员重载如何工作 - Can I overload an overloaded operator? How does Operator Overloading work 此模板类型推导和重载解析如何工作? - How does this template type deduction and overload resolution work? 重载解析如何在private修饰符的上下文中起作用? - How does overload resolution work in the context of private modifier?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM