赋值运算符在派生 class 中不可用
Assignment operator not available in derived class
基 class 中的赋值运算符似乎在派生 class 中不可用。鉴于此代码:
#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 说:
error: no match for 'operator=' (operand types are 'B' and 'int')
发生了什么事?
为了使其工作,您需要将 operator=
纳入 B
的范围:
class B : public A
{
public:
using A::operator=;
};
根据标准[class.copy.assign/8]:
Because a copy/move assignment operator is implicitly declared for a
class if not declared by the user, a base class copy/move assignment
operator is always hidden by the corresponding assignment operator of
a derived class (16.5.3).
所以,因为B::operator=
已经被隐式声明,所以它被隐藏了A::operator=
,如果你想使用它需要你把它引入范围。
进一步引用标准 [over.ass/1]
An assignment operator shall be implemented by a non-static member
function with exactly one parameter. Because a copy assignment
operator operator= is implicitly declared for a class if not declared
by the user (15.8), a base class assignment operator is always hidden
by the copy assignment operator of the derived class.
重点是我的。
问题是编译器会为B
class添加隐式赋值运算符,声明为
B& operator=(const B&);
此运算符将隐藏来自A
的运算符,因此编译器不会知道它。
解决方案是告诉编译器也使用来自 A
的运算符和 using
关键字:
class B : public A
{
public:
using A::operator=;
};
正如其他现有答案所指出的,B
的隐式生成的赋值运算符隐藏了 A
中定义的赋值运算符。对于基类中的任何非虚拟成员函数都是如此 class,这里唯一的特长是自动生成的赋值运算符。
但首先要弄清楚你是否真的想这样做。假设您的 class B
有需要以某种方式初始化的数据成员。使用来自 A
的赋值如何影响这些数据成员? A
对其派生的 class 数据成员一无所知,它们将保持不变。查看以下场景,其中赋值运算符已通过 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.
所以是的,这是可能的,但容易出错且危险,尤其是在涉及到子的未来修改时class。
每个 class 至少有一个赋值运算符隐式定义,而我们自己没有提供。
并且当派生 class 中的成员函数定义为与基 class 中的成员同名时,它会隐藏该名称的所有基 class 定义.
您可以使用 using 声明,但要注意它会提取 所有 名为 operator=
的成员并允许这样的代码:
A a;
B b;
b = a;
这有点可疑。
基 class 中的赋值运算符似乎在派生 class 中不可用。鉴于此代码:
#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 说:
error: no match for 'operator=' (operand types are 'B' and 'int')
发生了什么事?
为了使其工作,您需要将 operator=
纳入 B
的范围:
class B : public A
{
public:
using A::operator=;
};
根据标准[class.copy.assign/8]:
Because a copy/move assignment operator is implicitly declared for a class if not declared by the user, a base class copy/move assignment operator is always hidden by the corresponding assignment operator of a derived class (16.5.3).
所以,因为B::operator=
已经被隐式声明,所以它被隐藏了A::operator=
,如果你想使用它需要你把它引入范围。
进一步引用标准 [over.ass/1]
An assignment operator shall be implemented by a non-static member function with exactly one parameter. Because a copy assignment operator operator= is implicitly declared for a class if not declared by the user (15.8), a base class assignment operator is always hidden by the copy assignment operator of the derived class.
重点是我的。
问题是编译器会为B
class添加隐式赋值运算符,声明为
B& operator=(const B&);
此运算符将隐藏来自A
的运算符,因此编译器不会知道它。
解决方案是告诉编译器也使用来自 A
的运算符和 using
关键字:
class B : public A
{
public:
using A::operator=;
};
正如其他现有答案所指出的,B
的隐式生成的赋值运算符隐藏了 A
中定义的赋值运算符。对于基类中的任何非虚拟成员函数都是如此 class,这里唯一的特长是自动生成的赋值运算符。
但首先要弄清楚你是否真的想这样做。假设您的 class B
有需要以某种方式初始化的数据成员。使用来自 A
的赋值如何影响这些数据成员? A
对其派生的 class 数据成员一无所知,它们将保持不变。查看以下场景,其中赋值运算符已通过 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.
所以是的,这是可能的,但容易出错且危险,尤其是在涉及到子的未来修改时class。
每个 class 至少有一个赋值运算符隐式定义,而我们自己没有提供。
并且当派生 class 中的成员函数定义为与基 class 中的成员同名时,它会隐藏该名称的所有基 class 定义.
您可以使用 using 声明,但要注意它会提取 所有 名为 operator=
的成员并允许这样的代码:
A a;
B b;
b = a;
这有点可疑。