基类中的赋值运算符似乎在派生类中不可用。给出以下代码:
#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”)
发生了什么事?
答案 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=;
};