派生类中不可用的赋值运算符
Posted
技术标签:
【中文标题】派生类中不可用的赋值运算符【英文标题】:Assignment operator not available in derived class 【发布时间】:2019-06-30 07:00:52 【问题描述】:基类中的赋值运算符在派生类中似乎不可用。鉴于此代码:
#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')
发生了什么?
【问题讨论】:
【参考方案1】:正如其他现有答案所指出的,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.
所以是的,这是可能的,但容易出错且很危险,尤其是在将来修改子类时。
【讨论】:
它的行为没有什么不同,任何其他方法都会出现同样的问题。 @spectras “同样的问题” ??通常方法由派生类继承,无需进一步措施即可使用。编译器不会隐式声明任何其他方法 @user463035818 这里的问题是名称隐藏。请参阅一些程序员老兄的回答。只要派生类中的方法与基类中的方法同名,您就会遇到这个问题^^ @spectras 好的,谢谢,现在我明白你的意思了,虽然 OP 没有在派生中声明operator=
,而且它在隐藏方面很特别
最好的答案,imo,因为它解决了为什么隐藏赋值运算符是可取的,以及将其拖入的警告。【参考方案2】:
为了使其工作,您需要将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),基类赋值运算符始终隐藏 由派生类的复制赋值运算符。
重点是我的。
【讨论】:
【参考方案3】:问题是编译器会为B
类添加一个隐式赋值运算符,声明为
B& operator=(const B&);
此运算符会将运算符隐藏A
,因此编译器不会知道它。
解决方案是告诉编译器也使用 A
中的运算符和 using
关键字:
class B : public A
public:
using A::operator=;
;
【讨论】:
这不只是因为B
隐藏A::operator=
中隐式声明的复制赋值吗?
@spectras 是的,这是真的,这就是我更新答案的原因(就在你发表评论时)。【参考方案4】:
当我们自己不提供时,每个类至少隐式定义了一个赋值运算符。
当派生类中的成员函数被定义为与基类中的成员同名时,它会隐藏该名称的所有基类定义。
您可以使用 using 声明,但请注意,它将拉出 所有名为 operator=
的成员并允许使用如下代码:
A a;
B b;
b = a;
这有点可疑。
【讨论】:
我实际上必须阅读Mark's answer 才能理解您的第二段,但是一旦我了解到您的回答非常有用。以上是关于派生类中不可用的赋值运算符的主要内容,如果未能解决你的问题,请参考以下文章