默认赋值运算符有权访问基类的私有成员
Default assignment operator has access to private members of base class
我的问题很容易用这个例子来解释:
http://pastebin.com/VDBE3miY
class Vector3
{
float _x;
float _y;
float _z;
public :
/// constructors and stuff
};
class Point : public Vector3
{
// some BS
Point(float _x):Vector3(float _x)
{}
};
main()
{
Point aPoint(3);
Point anotherPoint(4);
// WHY DOES THIS WORK and copy _x,_y & _z properly
aPoint = anotherPoint;
}
基本上,我不明白为什么派生类的=
可以复制_x
、_y
和_z
,即使它不应该访问它们,因为它们是私有的。
aPoint = anotherPoint;
此行触发Point::operator=
(赋值运算符)的调用,该调用之所以存在,是因为编译器生成了默认实现。此默认实现对类的所有成员执行赋值操作,并调用基类的赋值运算符Vector3::operator=
。反过来,这是Vector3
的成员功能,因此可以访问所有私有成员,并复制这些成员。
(编辑)引用C++11标准来支持这个答案:
(§12.8/28)非联合类 X 的隐式定义的复制/移动赋值运算符对其子对象执行成员复制/移动赋值。首先按照 X 在基本说明符列表中的声明顺序分配 X 的直接基类,然后按照它们在类定义中声明的顺序分配 X 的直接非静态数据成员。设 x 是函数的参数,或者对于移动运算符,是引用参数的 x值。每个子对象都以适合其类型的方式分配:
— 如果子对象是类类型,就像通过调用 operator= 将子对象作为对象表达式一样 以及 x 的相应子对象作为单个函数参数(好像通过显式限定;即忽略更多派生类中任何可能的虚拟覆盖函数);
— 如果子对象是一个数组,则以适合元素类型的方式分配每个元素;
— 如果子对象是标量类型,则使用内置赋值运算符。
其他一些(现已部分删除)答案提到了赋值操作执行按位复制的想法。这有一定的道理:如果你的类或结构定义了 POD(普通旧数据)类型,那么它在所有实际目的上都与 C 结构相同。在这种情况下,可以通过执行memcpy
来复制它,因此您可以将赋值操作视为基本上等效于按位复制。但是,为什么这是一种有效的思考方式,那就是上面的§12.8/28,这也适用于非POD类型。
另请注意,从您的代码中不一定清楚您的数据类型是 POD。你在基类中提到了构造函数和东西:如果这涉及非平凡的复制构造函数、赋值运算符或可能的虚函数,那么你的数据类型就不再是 POD。
关于评论中的问题:为了从派生类实现中调用基类赋值运算符,只需调用它:
struct Base
{
};
struct Derived : Base
{
Derived &operator=(const Derived &other)
{ Base::operator=(other); return *this; }
};
因为调用了 Vector3 的默认复制运算符(浅拷贝)。
因为编译器生成赋值运算符
Point& operator=(Point const& rhs)
{
Vector3::operator=(rhs);
return *this;
}
Vector3& operator=(Vector3 const& rhs)
{
// A class is a friend of irself.
// So an object of Type A can read any other object of type A
_x = rhs._x;
_y = rhs._y;
_z = rhs._z;
return *this;
}
- 派生类看不到基类成员
- C++11: 如何访问派生类中的基类成员?
- Qml 未收到基类成员变量的更新值
- 指向从指针派生类成员函数的指针,指向基类成员函数
- 初始化基类成员 (c++) 的首选方法
- 访问多级复合关系中的基类成员
- 允许从特定派生类访问基类成员
- 在派生类的成员联合中包含继承的基类成员
- 由派生类设置的 constexpr 基类成员
- 从派生类调用的抽象基类成员函数
- 从抽象基类访问另一个基类成员
- C++派生类访问基类成员
- 不能引用派生模板类中的基类成员
- C2694 在析构函数上,当基类成员的析构函数具有非空 noexcept 说明符和主体时
- 在Visual Studio 2017中,通过扩展每个参数包来呼叫基类成员失败
- 在C 中访问带有不正确的下属的基类成员
- C++将基类成员链接到派生类成员
- 从基类成员函数返回派生类的实例
- 从指针到基类成员的模板推导
- 是否可以从派生类中排除基类成员?