繁体   English   中英

默认赋值运算符可以访问基类的私有成员

[英]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的直接基类首先按照它们在base-specifier-list中的声明顺序进行分配,然后按在类定义中声明的顺序分配X的直接非静态数据成员。 。 令x为函数的参数,或者对于move运算符,为引用该参数的xvalue。 每个子对象都以适合其类型的方式分配:

—如果子对象是类类型,则好像是通过调用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;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM