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

Assignment operator not available in derived class

提问人:Montaner 提问时间:2/6/2019 最后编辑:Soner GönülMontaner 更新时间:2/6/2019 访问量:2100

问:

基类中的赋值运算符似乎在派生类中不可用。给定以下代码:

#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”)

发生了什么事情?

C++ 继承 赋值运算符

评论


答:

20赞 Mark Ingram 2/6/2019 #1

为了让它工作,你需要将 the 引入 的范围: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= 如果未声明,则为类隐式声明 对于用户 (15.8),基类赋值运算符始终处于隐藏状态 由派生类的复制赋值运算符。

重点是我的。

9赞 Some programmer dude 2/6/2019 #2

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

B& operator=(const B&);

这个运算符会隐藏运算符,所以编译器不会知道它。A

解决方案是告诉编译器也使用带有关键字的运算符 from:Ausing

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

评论

0赞 spectras 2/6/2019
这难道不是因为隐藏了隐含声明的副本分配吗?BA::operator=
0赞 Some programmer dude 2/6/2019
@spectras 是的,这是真的,这就是为什么我更新了答案(就在您发表评论时)。
10赞 lubgr 2/6/2019 #3

正如其他现有答案所指出的,隐式生成的赋值运算符 隐藏了 中定义的赋值运算符。对于基类中的任何非虚拟成员函数都是如此,这里唯一的专长是自动生成的赋值运算符。BA

但首先要弄清楚你是否真的想这样做。想象一下,您的类具有需要以某种方式初始化的数据成员。使用赋值 from 如何影响这些数据成员? 不知道其派生的类数据成员的任何内容,它们将保持不变。请看以下方案,其中赋值运算符已通过 using 指令可用:BAA

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.

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

评论

1赞 spectras 2/6/2019
它的行为没有不同,任何其他方法都会出现相同的问题。
0赞 463035818_is_not_an_ai 2/6/2019
@spectras“同样的问题”??通常,Mehtod 由派生类继承,无需进一步措施即可使用。编译器不会隐式声明任何其他方法
0赞 spectras 2/6/2019
@user463035818这里的问题是隐藏名称。看一些程序员家伙的答案。每当派生类中的方法与基类中的方法同名时,您都会遇到此问题^^
0赞 463035818_is_not_an_ai 2/6/2019
@spectras好的,谢谢,现在我明白你的意思了,虽然 OP 没有在派生中声明 a,而且它在隐藏方面很特别operator=
1赞 naomimyselfandi 2/6/2019
最好的答案是 imo,因为它解决了为什么隐藏赋值运算符是可取的,以及将其拖入的注意事项。
28赞 StoryTeller - Unslander Monica 2/6/2019 #4

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

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

您可以使用 using 声明,但请注意,它将拉取所有命名的成员并允许如下所示的代码:operator=

A a;
B b;
b = a;

这有点可疑。

评论

1赞 Tas 2/7/2019
我实际上必须阅读马克的回答才能理解你的第二段,但一旦我明白你的回答信息量很大。