2

这个例子很容易解释我的问题:

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,即使它不应该访问它们,因为它们是私有的。

4

3 回答 3

5
aPoint = anotherPoint;

这一行触发了Point::operator=(赋值运算符)的调用,它之所以存在是因为编译器生成了一个默认实现。此默认实现对类的所有成员执行赋值操作,并调用Vector3::operator=基类的赋值运算符。这又是一个成员函数,Vector3因此可以访问所有私有成员,并对其进行复制。


(编辑)引用 C++11 标准来支持这个答案:

(§12.8/28) 非联合类 X 的隐式定义的复制/移动赋值运算符执行其子对象的成员复制/移动赋值。首先分配 X 的直接基类,按照它们在基说明符列表中的声明顺序,然后按照它们在类定义中声明的顺序分配 X 的直接非静态数据成员. 令 x 为函数的参数,或者对于移动运算符,为引用参数的 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; }
};
于 2012-11-26T05:56:13.033 回答
0

因为编译器生成赋值运算符

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;
}
于 2012-11-26T06:17:23.013 回答
0

因为调用了 Vector3 的默认复制操作符(浅复制)。

于 2012-11-26T05:47:15.617 回答