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)
所以是的,这是可能的,但是容易出错并且很危险,特别是在涉及子类的未来修改时.
问题是编译器将为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)