首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >派生类中不可用的赋值运算符

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

Stack Overflow用户
提问于 2019-02-06 02:44:25
回答 4查看 1.9K关注 0票数 31

基类中的赋值运算符在派生类中似乎不可用。鉴于这一守则:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#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')

这是怎么回事?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2019-02-06 02:50:10

当我们自己不提供赋值操作符时,每个类都至少有一个隐含定义的赋值运算符。

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

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
A a;
B b;
b = a;

有点令人怀疑。

票数 28
EN

Stack Overflow用户

发布于 2019-02-06 02:48:27

为了使其正常工作,您需要将operator=引入B的范围:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class B : public A
{
public:
using A::operator=;
};

根据标准的class.copy.assign.class.copy.assign.分配/8

由于如果用户不声明,则为类隐式声明复制/移动赋值操作符,因此派生类的相应赋值运算符(16.5.3)总是隐藏基类副本/移动赋值运算符。

因此,因为B::operator=是隐式声明的,所以它有隐藏的A::operator=,如果您想要使用它,就需要将它带入作用域。

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

赋值操作符应由具有精确一个参数的非静态成员函数实现.,因为如果用户没有声明一个类,则为一个类隐式声明一个副本赋值操作符(15.8),因此派生类的副本赋值操作符总是隐藏基类赋值操作符。

重点是我的。

票数 20
EN

Stack Overflow用户

发布于 2019-02-06 02:49:20

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

但首先要弄清楚你是否真的想这么做。假设您的类B有需要以某种方式初始化的数据成员。使用来自A的赋值是如何影响这些数据成员的?A不知道其派生类数据成员的任何信息,它们将不受影响。查看以下场景,其中通过using指令使赋值操作符可用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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.

因此,是的,这是可能的,但容易出错和危险,特别是当涉及到未来的修改子类。

票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54551695

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文