考虑一个 class 用来表现颜色,然后手动写出(而非由编译器创建) copy函数使得外界对它们的调用会被记录( logged)下来:
void logcall(const std::string& funcname); //日志打印
class Color{
public:
Color(const Color& rhs);
Color& operator(const Color& rhs);
private:
string color;
};
Color::Color(const Color& rhs) : name(rhs.name) { //复制xhs的数据
logcall("Color copy");
}
Color& Color::operator=(const Color& rhs) {
logcall ("Color copy assignment operator");
name = rhs.name; //复制rhs的数据
return *this;
}
到现在为止每一件事情看起来都很好,但当添加一个新的成员变量时:
class Number {...}; //数量
class Color{
public:
... //同上面代码
private:
string name;
Number num;
};
这时候的 copying函数执行的是局部拷贝:它们的确复制了color的name,但没有复制新添加的Number num。大多数编译器对此不会理会,即使在最高警告级别。结论很明显:如果你为 class添加一个成员变量,你必须同时修改copy函数。(你也需要修改 class的所有构造函数以及任何非标准形式的operator=,如果你忘记了,编译器也不会提醒你。
一旦发生继承,可能会造成一些麻烦,试考虑:
class ChildColor: public Color {
public:
ChildColor(const ChildColor& rhs):
ChildColor& operator=(const ChildColor& rhs);
private:
int priority;
};
ChildColor::ChildColor(const ChildColor& rhs) : priority(rhs.priority) {
logcall("ChildColor copy");
}
ChildColor& ChildColor::operator=(const ChildColor& rhs) {
logcall("ChildColorcopy assignment operator");
priority =rhs.priority;
return *this;
}
ChildColor的 copy函数看起来好像复制了 ChildColor内的每一项,它复制了 ChildColor的成员变量,但每个 ChildColor还内含它所继承的 Color成员变量副本,而那些成员变量却未被复制。 ChildColor的copy构造函数并没有指定实参传给其 base class构造函数(也就是说它在它的成员初值列中没有提到Color,因此,此 ChildColor对象的 Color成分会被不带实参的Color构造函数(即 default构造函数一一必定有一个,否则无法通过编译)初始化。 default构造函数将针对name和num执行默认的初始化动作。
这时你必须很小心地也复制其 base class成分。那些成分往往是 private,所以你无法直接访问它们,你应该让子类的 copy函数调用相应的父类函数:
//调用父类的copy构造函数
ChildColor::ChildColor(const ChildColor& rhs):Color(rhs),priority(rhs.priority) {
logcall("ChildColor copy");
}
ChildColor& ChildColor::operator=(const ChildColor& rhs){
logcall ("ChildColor copy operator");
Color::operator=(rhs); //对父类成分进行赋值动作
priority = rhs.priority.
return *this;
};