[英]Default assignment operator has access to private members of base class
My problem is very easily explained by this example : 这个例子很容易解释我的问题:
http://pastebin.com/VDBE3miY 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;
}
Basically, I am at a loss to understand why the =
for the derived class can copy _x
, _y
and _z
, even though it shouldn't have access to them since they are private. 基本上,我不知所措,为什么派生类的=
为什么可以复制_x
, _y
和_z
,即使由于它们是私有的也无法访问它们。
aPoint = anotherPoint;
This line triggers a call of Point::operator=
(the assignment operator), which exists because the compiler generates a default implementation. 该行触发Point::operator=
(赋值运算符)的调用,该调用之所以存在是因为编译器会生成默认实现。 This default implementation performs assignment operations for all members of the class, as well as calling Vector3::operator=
, the assignment operator of the base class. 此默认实现对类的所有成员执行赋值操作,并调用Vector3::operator=
(基类的赋值运算符)。 This, in turn, is a member function of Vector3
and therefore has access to all private members, which it makes copies of. 这又是Vector3
的成员函数,因此可以访问所有私有成员,并对其进行复制。
(EDIT) A quote from the C++11 Standard to back this answer: (编辑)来自C ++ 11标准的引用以支持此答案:
(§12.8/28) The implicitly-defined copy/move assignment operator for a non-union class X performs memberwise copy-/move assignment of its subobjects. (第12.8 / 28节)非工会类X的隐式定义的复制/移动分配操作符对其子对象执行成员式复制/移动分配。 The direct base classes of X are assigned first, in the order of their declaration in the base-specifier-list, and then the immediate non-static data members of X are assigned, in the order in which they were declared in the class definition. X的直接基类首先按照它们在base-specifier-list中的声明顺序进行分配,然后按在类定义中声明的顺序分配X的直接非静态数据成员。 。 Let x be either the parameter of the function or, for the move operator, an xvalue referring to the parameter. 令x为函数的参数,或者对于move运算符,为引用该参数的xvalue。 Each subobject is assigned in the manner appropriate to its type: 每个子对象都以适合其类型的方式分配:
— if the subobject is of class type, as if by a call to operator= with the subobject as the object expression and the corresponding subobject of x as a single function argument (as if by explicit qualification; that is, ignoring any possible virtual overriding functions in more derived classes); —如果子对象是类类型,则好像是通过调用operator =来实现的,子对象作为对象表达式,x的对应子对象作为单个函数参数(就像通过显式限定;也就是说,忽略任何可能的虚拟覆盖)更多派生类中的功能);
— if the subobject is an array, each element is assigned, in the manner appropriate to the element type; —如果子对象是数组,则以适合元素类型的方式分配每个元素;
— if the subobject is of scalar type, the built-in assignment operator is used. —如果子对象是标量类型,则使用内置的赋值运算符。
Some of the other (now partly deleted) answers mentioned the idea of a bitwise copy performed by the assignment operation. 其他一些答案(现在已部分删除)提到了通过赋值操作执行按位复制的想法。 There is some truth in this: If your class or struct defines a POD (plain old data) type, it is for all practical purposes identical to a C struct. 这样做有一个道理:如果您的类或结构定义了POD(普通旧数据)类型,则在所有实际应用中它都与C结构相同。 In that case, it can be copied by performing memcpy
, therefore you can think of the assignment operation as being basically equivalent to a bitwise copy. 在那种情况下,可以通过执行memcpy
复制它,因此您可以认为分配操作基本上等效于按位复制。 But the reason why this is a valid way of thinking about it is §12.8/28 above, and that applies to non-POD types as well. 但是,这是一种有效的思考方式,其原因在于上文的§12.8/ 28,它也适用于非POD类型。
Also note that from your code it is not necessarily clear that your data type is POD. 还要注意,从您的代码中,不一定清楚您的数据类型是POD。 You mentioned constructors and stuff in the base class: If this involves non-trivial copy constructors, assignment operators or possibly virtual functions, then your data type is no longer POD. 您在基类中提到了构造函数和相关内容 :如果涉及非平凡的拷贝构造函数,赋值运算符或可能的虚函数,则您的数据类型不再是POD。
About the question in the comment: In order to call the base-class assignment operator from within the derived-class implementation, just call it: 关于注释中的问题:为了从派生类实现中调用基类赋值运算符,只需调用它:
struct Base
{
};
struct Derived : Base
{
Derived &operator=(const Derived &other)
{ Base::operator=(other); return *this; }
};
因为调用了Vector3的默认复制运算符(浅复制)。
Because the compiler generate assignment operator(s) 因为编译器会生成赋值运算符
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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.