赋值运算符在派生类中不可用

Mon*_*ner 30 c++ inheritance assignment-operator

基类中的赋值运算符似乎在派生类中不可用.鉴于此代码:

#include <iostream>

class A{
    int value;
public:
    A& operator=(int value){
        this->value = value;
        return *this;
    }
};

class B : public A{};

int main(){
    B b;
    b = 0; // Does not work
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

GCC 6.4说:

错误:'operator ='不匹配(操作数类型为'B'和'int')

怎么了?

Sto*_*ica 27

当我们自己不提供一个赋值运算符时,每个类至少有一个赋值运算符.

当派生类中的成员函数定义为与基类中的成员同名时,它会隐藏该名称的所有基类定义.

您可以使用using声明,但要注意它将拉出所有名为的成员operator=并允许这样的代码:

A a;
B b;
b = a;
Run Code Online (Sandbox Code Playgroud)

这有点可疑.


Mar*_*ram 20

为了使它工作,你需要operator=进入B范围:

class B : public A
{
public:
using A::operator=;
};
Run Code Online (Sandbox Code Playgroud)

根据标准[class.copy.assign/8]:

因为如果未由用户声明,则为类隐式声明复制/移动赋值运算符,则基类复制/移动赋值运算符始终由派生类的相应赋值运算符隐藏(16.5.3).

因此,因为B::operator=已经隐式声明,它已隐藏A::operator=,如果您想使用它,则需要您将其带入范围.

进一步引用标准[over.ass/1]

赋值运算符应由具有一个参数的非静态成员函数实现.因为如果没有由用户声明,则为类隐式声明了复制赋值运算符operator =(15.8),基类赋值运算符总是被派生类的复制赋值运算符隐藏.

重点是我的.


lub*_*bgr 10

正如其他现有答案所指出的,隐式生成的赋值运算符B隐藏了定义的赋值运算符A.对于基类中的任何非虚拟成员函数都是如此,这里唯一的特性是自动生成的赋值运算符.

但首先要弄清楚你是否真的想要这样做.想象一下,您的类B具有需要以某种方式初始化的数据成员.如何使用分配来A影响这些数据成员?A它不知道它的派生类数据成员的任何东西,它们将保持不变.查看以下可通过using指令使赋值运算符可用的方案:

class B : public A {
   public:
      using A::operator=;

      int m = 0; // Default-initialize data member to zero
};

B b;
b.m = 42;
b = 0; // Doesn't touch B::m... intended? A bug? Definitely weird.
Run Code Online (Sandbox Code Playgroud)

所以是的,这是可能的,但是容易出错并且很危险,特别是在涉及子类的未来修改时.


Som*_*ude 9

问题是编译器将为B该类添加一个隐式赋值运算符,声明为

B& operator=(const B&);
Run Code Online (Sandbox Code Playgroud)

此运算符将隐藏运算符A,因此编译器不会知道它.

解决方案是告诉编译器也使用A带有using关键字的运算符:

class B : public A
{
public:
    using A::operator=;
};
Run Code Online (Sandbox Code Playgroud)