Effective C++ Note 16: assign to all data members in operator =
When we overload the operator =, it is important that we assign to all data members.
This may seem easy when the class is not derived, but things get more complex when inheritance joins the party.
Consider the following code:
class Base {
public:
Base(int initialValue = 0): x(initialValue) {}
private:
int x;
};
class Derived: public Base {
public:
Derived(int initialValue)
: Base(initialValue), y(initialValue) {}
Derived& operator=(const Derived& rhs);
private:
int y;
};
// erroneous assignment operator
Derived& Derived::operator=(const Derived& rhs)
{
if (this == &rhs) return *this; // see Item 17
y = rhs.y; // assign to Derived's
// lone data member
return *this; // see Item 15
}
int main()
{
Derived d1(0); // d1.x = 0, d1.y = 0
Derived d2(1); // d2.x = 1, d2.y = 1
d1 = d2; // d1.x = 0, d1.y = 1!
....
}
d1.x here is not changed, because Derived::operator = will not call Base::operator = automatically. You will have to do it explicitly. So the right code may be like this:
Derived& Derived::operator=(const Derived& rhs)
{
if (this == &rhs) return *this;
Base::operator =(rhs);
y = rhs.y;
return *this;
}
Here we make an explicit call to Base::operator =. However, some compilers may reject this kind of call to base class's assignment operator if the operator is generated by the compiler. In this case, we have to do it this way:
static_cast<Base&>(*this) = rhs;
It is important that the cast be to a reference to a Base object.
The same problem occurs to the copy constructor if we write a copy constructor for Derived like this:
Derived(const Derived& rhs) // erroneous copy
: y(rhs.y) {} // constructor
This code won't work properly. Though the the constructor of Base will be envoked before the copy constructor of class Derived, it is the default constructor of Base that will be called. So what we have to do is to call the copy constructor of Base explicitly. The following code show how:
Derived(const Derived& rhs): Base(rhs), y(rhs.y) {}