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

时间:2019-02-06 10:44:25

标签: 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;
}

GCC 6.4说:

  

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

发生了什么事?

4 个答案:

答案 0 :(得分:26)

在我们自己不提供的时候,每个类至少都有一个隐式定义的赋值运算符。

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

您可以使用using声明,但要警告它会拉 all 个名为operator=的成员,并允许这样的代码:

A a;
B b;
b = a;

有些怀疑。

答案 1 :(得分:18)

要使其正常运行,您需要将operator=纳入B的范围内:

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

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

  

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

因此,由于B::operator=已隐式声明,因此它已隐藏A::operator=,如果要使用它,则需要将其带入范围。

标准[over.ass / 1]中的其他报价

  

赋值运算符应由非静态成员实现   仅具有一个参数的函数。 因为有副本分配   如果未声明,则为类隐式声明operator operator =   用户(15.8)始终隐藏基类分配运算符   

强调是我的。

答案 2 :(得分: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.

是的,这是可能的,但是容易出错且很危险,尤其是在涉及子类的将来修改时。

答案 3 :(得分:8)

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

B& operator=(const B&);

该运算符将从A 隐藏 运算符,因此编译器将对此一无所知。

解决方案是告诉编译器也将A中的运算符与using关键字一起使用:

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