当我们指定一个class object给另一个class object时,通常有三种选择:
什么都不做,实施默认的行为。
提供一个explicit copy assignment operator。
显式地拒绝指定一个class object给另一个class object,声明为private(并且此时不同函数的定义,一旦某个member function或friend企图影响一份拷贝,程序链接时就会失败)。
利用Point class来帮助讨论:
class Point {
public:
Point(float x = 0.0, float y = 0.0);
private:
float _x, _y;
};
如果不对class point提供copy assignment operator,光是依赖默认的memberwise copy,编译器不会产生出一个实例,因为此class已经有了bitwise copy语意,所以implicit copy assignment operator被视为毫无用处,根本不会合成出来。
一个class对于默认的copy assignment operator,在以下情况下,不会表现出bitwise copy语意
当class内含一个class object,而其class有个copy assignment operator时
当一个class的base class有个copy assignment operator是
当一个class声明了任何virtual function(一定不要拷贝右端class object的vptr地址,因为他可能是一个derived class object)时
当一个class继承自一个virtual base class(不论base class有没有copy operator)时
如果没有为Point3d设定一个copy assignment operator,编译器就会为其合成一个:
inline Point3d&
Point3d::operator=(point3d* this, const Point3d& p) {
this->Point::operator=(p); //base class operator=
_z = p._z; //memberwise copy
return *this;
}
copy assignment operator缺乏一个member assignment list,类似于成员初值列,比如
inline Point3d&
Point3d::operator=(const Point3d& p)
: Point(p), _z(p._z) { } //这是不支持的,只能写成上面合成的形式
缺少 member assignment list,编译器一般就没有办法压抑上层 base class 的 copy operator 被调用。还是考虑之前的继承体系,类 Vertex 虚拟自 Point ,并且从 Point3d 和 Vertex 派生出Vertex3d。则copy operator 如下:
inline Vertex&
Vertex operator=(const Vertex& v) {
this->Point::operator=(v);
_next = v._next;
return *this;
}
inline Vertex3d&
Vertex operator=(const Vertex3d& v) {
this->Point::operator=(v);
this->Point3d::operator=(v);
this->Vertex::operator=(v);
return *this;
}
编译器如何在 Point3d 和 Vertex 的 copy assignment operator 压制 Point 的 copy assignment operator呢?constructor 中的解决办法是添加一个额外的参数 __most_derived。解决办法是:为copy assignment operator 提供分发函数(split functions)以支持这个 class 称为 most-derived class或者成为中间的 base class。
尽可能不要允许一个 virtual base class 的拷贝操作,更进一步,不要在任何 virtual base class 中声明数据