派生类是否间接继承基的赋值运算符?

Do derived classes indirectly inherit base's assignment operator?

本文关键字:赋值运算符 继承 是否 派生      更新时间:2023-10-16

我试图理解这种行为,但似乎我没有。请参阅此代码:

#include <iostream>
using namespace std;
class Base
{
public:
    void operator=(const Base& rf)
    {
        cout << "base operator=" << endl;
        this->y = rf.y;
    }
    int y;
    Base() : y(100) { }
};
class Derived : public Base
{
public:
    int x;
    Derived() : x(100) { }
};
int main()
{
    Derived test;
    Derived test2;
    test2.x = 0;
    test2.y = 0;
    test.operator=(test2); // operator auto-generated for derived class but...
    cout << test.x << endl << test.y << endl;
    cin.ignore();
    return 0;
}

程序输出:

> base operator=
>  0
>  0

现在我感到困惑的是:该规则表示派生类永远不会继承 assigment 运算符,而是创建自己的 operator=但是在此示例中,基的operator=在派生类上被调用。

其次,我能够在派生类

上显式调用同化运算符,而派生类中没有显式定义该运算符。

现在,如果我理解正确,这意味着任何用户定义的 base 运算符总是在派生类上被调用?

生成的会自动调用基类赋值运算符。

// generated version looks basically like this
Derived& operator=(Derived const& other){
  Base::operator=(static_cast<Base const&>(other));
  x = other.x;
  return *this;
}

演员阵容的存在是为了避免意外调用像这样的模板Base::operator=

template<class Other>
Base& operator=(Other const& other); // accepts everything

或者像这样奇怪的:

// forward-declare 'Derived' outside of 'Base'
Base& operator=(Derived const& other); // accepts derived class (for whatever reason)

其次,我能够在派生类

上显式调用同化运算符,而派生类中没有显式定义该运算符。

如果您不这样做并且您的类允许它(即没有引用成员和其他一些晦涩的规则(,编译器会自动声明一个赋值运算符,如果您实际在某处使用它,则另外定义它。

编译器生成的赋值运算符调用每个子对象的赋值运算符。 这包括基类和非静态成员变量。

该标准说(第12.8节[class.copy](:

如果类定义未显式声明复制赋值运算符,则隐式声明一个。 如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制赋值运算符定义为已删除; 否则,它被定义为默认值 (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&)

非联合类的隐式定义的复制/移动赋值运算符X执行其子对象的成员复制/移动赋值。 首先按照X基说明符列表中的声明顺序分配的直接基类,然后按照它们在类定义中声明的顺序分配X的直接非静态数据成员。设x函数的参数 或者,对于移动运算符,指指参数的 x值。 每个子对象都以适合其类型的方式分配:

  • 如果子对象是类类型,则好像通过调用 operator= 将子对象作为对象表达式,将x的相应子对象作为单个函数参数(好像通过显式限定;即忽略更多派生类中任何可能的虚拟覆盖函数(;
  • 如果子对象是数组,则以适合元素类型的方式分配每个元素;
  • 如果子对象是标量类型,则使用内置赋值运算符。

未指定表示虚拟基类的子对象是否由隐式定义的复制赋值运算符多次赋值。

这是因为隐

式定义的运算符 = 调用基类运算符 =。请参阅常见问题简版:

我正在创建一个派生类;赋值运算符是否应该调用基类的赋值运算符?

是(如果需要首先定义赋值运算符(。

如果定义自己的赋值运算符,编译器不会自动为您调用基类的赋值运算符。除非基类的赋值运算符本身被破坏,否则应从派生类的赋值运算符显式调用它(同样,假设您首先创建了一个赋值运算符(。

但是,如果不创建自己的赋值运算符,编译器为您创建的赋值运算符将自动调用基类的赋值运算符。

4 件事永远不会被继承构造 函数复制构造函数赋值运算符破坏者

即使你没有写赋值运算符,你的代码也会很好。每当使用赋值运算符时,编译器都会确保调用每个成员对象和基类的赋值运算符。