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

发布于 2024-12-26 22:54:02 字数 932 浏览 4 评论 0原文

我试图理解这种行为,但似乎我不明白。请看这段代码:

#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

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

其次,我能够在派生类上显式调用赋值运算符,而该运算符并未在派生类中显式定义。

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

I'm trying to understand this behaviour but it seems I don't. Please see this code:

#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;
}

PROGRAM OUTPUT:

> base operator=
>  0
>  0

Now where I'm confused is:
The rule says that a derived class never inherits the assigment operator, instead it creates its own operator= however in this example base's operator= gets invoked on the derived class.

Second I was able to explicitly invoke an assigment operator on a derived class, which isn't in turn explicitly defined in the derived class.

Now if I understand it correctly, this means that any user defined base's operator always gets invoked on the derived class?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

梦途 2025-01-02 22:54:02

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

// 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)

其次,我能够在派生类上显式调用赋值运算符,而该运算符并未在派生类中显式定义。

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

The generated ones automatically call the base-class assignment operator.

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

The cast is there to avoid an accidential call to a templated Base::operator= like this one:

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

Or a strange one like this:

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

Second I was able to explicitly invoke an assigment operator on a derived class, which isn't in turn explicitly defined in the derived class.

The compiler automatically declares an assignment operator if you do not and your class allows it (i.e., no reference members and some other arcane rules) and additionally defines it if you actually use it somewhere.

乜一 2025-01-02 22:54:02

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

该标准规定(第 12.8 节 [class.copy]):

如果类定义没有显式声明复制赋值运算符,则隐式声明一个。如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制赋值运算符被定义为已删除;否则,它被定义为默认(8.4)。如果类具有用户声明的复制构造函数或用户声明的析构函数,则不推荐使用后一种情况。类 X 的隐式声明的复制赋值运算符将具有以下形式

X& X::运算符=(const X&)

如果

  • X 的每个直接基类 B 都有一个复制赋值运算符,其参数类型为 const B&
    const volatile B&B,以及
  • 对于属于类类型 M(或其数组)的 X 的所有非静态数据成员,每个此类类类型都有一个复制赋值运算符,其参数的类型为 const M&const volatile M&M

否则,隐式声明的复制赋值运算符将具有以下形式

X& X::运算符=(X&)

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

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

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

The compiler-generated assignment operator calls the assignment operator of each subobject. That includes base classes and non-static member variables.

The standard says (section 12.8 [class.copy]):

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). 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::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
  • 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.

Otherwise, the implicitly-declared copy assignment operator will have the form

X&  X::operator=(X&)

and

The implicitly-defined copy/move assignment operator for a non-union class X performs memberwise copy/move assignment of its subobjects. The direct base classes of X are assigned first, in the order of their declaration in the base-specifier-list, and then the immediate non-static data members of X are assigned, in the order in which they were declared in the class definition. Let x be either the parameter of the function
or, for the move operator, an xvalue referring to the parameter. Each subobject is assigned in the manner appropriate to its type:

  • if the subobject is of class type, as if by a call to operator= with the subobject as the object expression and the corresponding subobject of x as a single function argument (as if by explicit qualification; that is, ignoring any possible virtual overriding functions in more derived classes);
  • if the subobject is an array, each element is assigned, in the manner appropriate to the element type;
  • if the subobject is of scalar type, the built-in assignment operator is used.

It is unspecified whether subobjects representing virtual base classes are assigned more than once by the implicitly-defined copy assignment operator.

末骤雨初歇 2025-01-02 22:54:02

这是因为隐式定义的运算符 = 调用基类运算符 =。请参阅常见问题解答精简版:

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

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

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

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

That's because the implicitly defined operator = calls the base classes operator =. See the FAQ lite:

I'm creating a derived class; should my assignment operator call my base class's assignment operator?

Yes (if you need to define an assignment operator in the first place).

If you define your own assignment operator, the compiler will not automatically call your base class's assignment operator for you. Unless your base class's assignment operator itself is broken, you should call it explicitly from your derived class's assignment operator (again, assuming you create one in the first place).

However if you do not create your own assignment operator, the one that the compiler creates for you will automatically call your base class's assignment operator.

堇年纸鸢 2025-01-02 22:54:02

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

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

4 things never get inherited
Constructor
Copy-constructor
Assignment operator
Destructor

Even you have not written the assignment operator your code will be Woking fine.
Whenever you use assignment operator compiler will make sure that assignment operator for each member object and base class get called.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文