如果没写赋值运算符的话,编译器会提供默认的,但这个默认的有时效果不好(参见条款11)。所以能否有个两全其美的办法,让编译器生成一个缺省的赋值运算符,然后再有选择地重写不喜欢的部分。这是不可能的!因为一旦重写了,编译器就不再提供默认的了。
重写赋值运算符时,必须对对象的每一个数据成员赋值:
初写这个类时当然很容易记住上面的原则,但同样重要的是,当类里增加新的数据成员时,也要记住更新赋值运算符函数。当涉及到继承时,情况就会更有趣,因为派生类的赋值运算符也必须处理 它的基类成员的赋值!看看下面:
逻辑上说,Derived 的赋值运算符应该像这样:
// erroneous assignment operator
不幸的是,它是错误的 。测试代码如下:
解决这个问题的办法是在 Derived::operator=中对 x 赋值。 但这不合法,因为 x 是 Base 的私有成员。 所以必须显式调用 Base的operator=。
但如果基类赋值运算符是编译器生成的 ,有些编译器会拒绝这种调用(见条款 45)。为了适应这种编译器,必须这样实现 Derived::operator=:
这里只是对 Derived 对象的 Base 部分赋值。 还要注意的重要一点是,转换的是 Base 对象的引用,而不是 Base 对象本身。 如果将*this 强制转换为 Base 对象,会导致调用 Base 的拷贝构造函数,创建出来的新对象(见条款 M19) 就成为了赋值的目标,而*this 保持不变。这不是所想要的结果。
另一个经常发生的和继承有关的类似问题是在实现派生类的拷贝构造函数 时。看看下面这个构造函数,其代码和上面刚讨论的类似:
类 Derived 展现了一个在所有 C++环境下都会产生的 bug:当 Derived 的 拷贝创建时,没有拷贝其基类部分。当然,这个 Derived 对象的 Base 部分还是创建了,但它是用 Base 的缺省构造函数创建的,成员 x 被初始化为 0(缺省构造函数的缺省参数值),而没有顾及被拷贝的对象的 x 值是多少!正确的写法如下:
现在,当用一个已有的同类型的对象来拷贝创建一个 Derived 对象时,它 的 Base 部分也将被拷贝了。