2

My problem is very easily explained by this example :

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.

jogojapan
  • 68,383
  • 11
  • 101
  • 131
angryInsomniac
  • 829
  • 2
  • 13
  • 27

3 Answers3

5
aPoint = anotherPoint;

This line triggers a call of Point::operator= (the assignment operator), which exists because the compiler generates a default implementation. 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. This, in turn, is a member function of Vector3 and therefore has access to all private members, which it makes copies of.


(EDIT) A quote from the C++11 Standard to back this answer:

(§12.8/28) The implicitly-defined copy/move assignment operator for a non-union class X performs memberwise copy-/move assignment of its subobjects. 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. Let x be either the parameter of the function or, for the move operator, an xvalue referring to the parameter. 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);

— 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. 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. 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.

Also note that from your code it is not necessarily clear that your data type is 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.


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; }
};
jogojapan
  • 68,383
  • 11
  • 101
  • 131
  • Ok , so say I want to overload the assignment operator of Point , to do a deep copy of certain specific member variables, is there any way to call Vector3::operator= from inside there ? Or I just need to make those members protected and then manually copy them. – angryInsomniac Nov 26 '12 at 06:09
  • Also , what do ya have to say about this : http://stackoverflow.com/questions/13559255/default-assignment-operator-has-access-to-private-members-of-base-class/13559416#13559416 – angryInsomniac Nov 26 '12 at 06:12
  • 1
    @angryInsomniac I think my answer was wrong, so I deleted it. This one looks correct to me. Btw, to call `Vector3::operator=()`, you do: `aPoint.Vector3::operator=(anotherPoint)`. – Nikos C. Nov 26 '12 at 06:21
  • @angryInsomniac I have added a few more detailed explanations. – jogojapan Nov 26 '12 at 06:28
0

Because the default copy operator of Vector3 is invoked (shallow copy).

Mario The Spoon
  • 4,799
  • 1
  • 24
  • 36
0

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;
}
Martin York
  • 257,169
  • 86
  • 333
  • 562
  • The cast would, imho not work if Point added some members to its definition , which it does in my implementation. – angryInsomniac Nov 26 '12 at 06:22
  • See: http://stackoverflow.com/a/1810320/14065 for the methods generated by the compiler. – Martin York Nov 26 '12 at 06:26
  • PS: The cast would have worked as `Point` is a `Vector3`. But I have simplified it for you. The point is the compiler automatically generates these methods (and they work (in a shallow copy way; which is what you want in most cases (where pointers are not concerned))). – Martin York Nov 26 '12 at 06:29