为啥继承的受保护运算符=()具有公共访问权限
Posted
技术标签:
【中文标题】为啥继承的受保护运算符=()具有公共访问权限【英文标题】:Why does inherited protected operator=() has public access为什么继承的受保护运算符=()具有公共访问权限 【发布时间】:2018-03-30 16:32:28 【问题描述】:声明为受保护的重载运算符=
对继承父类的子类公开访问。
#include <iostream>
class A
public:
A(char c) : i(c)
char i;
protected:
A& operator=(const A& rdm)
std::cout << "accessing operator=()" << std::endl;
i = 'x';
return *this;
;
class B : public A
public:
B(char c) : A(c)
;
int main(int ac, char** av)
B a('a');
B b('b');
std::cout << "a.i == " << a.i << std::endl;
a = b;
std::cout << "a.i == "<< a.i << std::endl;
编译时没有错误:
$ g++ -Wall -o test_operator ~/test_operator.cpp
$ ./test_operator
a.i == a
accessing operator=()
a.i == x
直接使用 A 不会编译。除了operator=()
之外的任何其他运算符重载都不会编译。
使用 g++ 4.4.7 和 7.3.0 以及 c++98 和 c++17 进行测试。
为什么在这种情况下operator=()
可以公开访问?
【问题讨论】:
而隐式运算符调用基类运算符。 三法则再次来袭。 你会保护它吗,编译器会不会编译失败,但会提示正在发生的事情。 【参考方案1】:B
中有一个隐式复制赋值运算符,具有 public
访问权限。
来自the C++11 Standard:
如果类定义没有显式声明复制赋值运算符,则隐式声明一个。如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制赋值运算符被定义为删除;否则,它被定义为默认值 ([dcl.fct.def])。如果类具有用户声明的复制构造函数或用户声明的析构函数,则不推荐使用后一种情况。类 X 的隐式声明的复制赋值运算符将具有以下形式
X& X::operator=(const X&)
如果
——
X
的每个直接基类B
都有一个复制赋值运算符,其参数类型为const B&
、const volatile B&
或B
,并且——对于
X
的所有非静态数据成员,它们属于类类型M
(或其数组),每个此类类型都有一个复制赋值运算符,其参数类型为const M&
,@ 987654337@或M
。否则,隐式声明的复制赋值运算符将具有以下形式
X& X::operator=(X&)
换句话说,你的代码表现得好像你有:
class B : public A
public:
B(char c) : A(c)
B& operator=(B const& rhs) A::operator==(rhs); return *this;
;
这里是你的更新版本,它演示了隐式声明的复制赋值运算符函数的行为。它表明B
没有继承A
的复制赋值运算符。
#include <iostream>
class A
public:
A(char c) : i(c)
char i;
protected:
A& operator=(const A& rdm)
std::cout << "accessing A::operator=()" << std::endl;
i = 'x';
return *this;
;
class X
public:
X& operator=(X const& rhs)
std::cout << "accessing X::operator=()" << std::endl;
return *this;
;
class B : public A
public:
B(char c) : A(c)
X x;
;
int main(int ac, char** av)
B a('a');
B b('b');
std::cout << "a.i == " << a.i << std::endl;
a = b;
std::cout << "a.i == "<< a.i << std::endl;
输出:
a.i == a
accessing A::operator=()
accessing X::operator=()
a.i == x
隐式声明/定义的复制赋值运算符的行为就像我们有:
B& operator=(B const& rhs)
A::operator==(rhs);
this.x = rhs.x;
return *this;
这与standard says:
非联合类
X
的隐式定义的复制/移动赋值运算符执行其子对象的成员复制/移动赋值。首先分配X
的直接基类,按照它们在base-specifier-list 中的声明顺序,然后分配X
的直接非静态数据成员,在它们在类定义中的声明顺序。
【讨论】:
A 类 X 具有自己的operator=
显示消息,以及 B 中类 X 的私有成员,可以帮助理解它不仅仅是继承的运算符:ideone.com/pJRpNP
你知道标准中的默认方法实现在哪里吗?
@Jean,你可以在timsong-cpp.github.io/cppwp/n3337/class.copy#28找到它。
哦,对了。我实际上正在寻找第 29 项!谢谢你的回答。以上是关于为啥继承的受保护运算符=()具有公共访问权限的主要内容,如果未能解决你的问题,请参考以下文章