前言
在三种情况下,会以一个 object 的内容作为另一个 class object 的初值:
- object明确初始化
class X{...};
X x;
X xx = x;
- object 被当作参数交与某个函数
extern void foo(X x);
void bar(){
X xx;
foo(xx);//作为第一个参数的初值(不明显的初始化)
}
- 函数返回值是一个 class object
X foo_bar(){
X xx;
...
return xx;
}
如果开发者已经明确定义了一个copy constructor 如下:
//copy constructor可以是多参数,其中有一个参数是其class type
X::X(const X& x);
Y::Y(const Y& y);
那么在大部分情况下,当 class object 以另一个同类实体作为初值时,上述 constructor 会被调用,这可能会导致一个暂时性 class object 的产生或程序代码发生改变(或二者都有)。
重新设定 Virtual Table 的指针
编译期间的扩张操作(只要有一个class声明了一个或多个virtual function):
增加一个 virtual function table(vtbl),内含每一个有作用的 virtual function 的地址。
一个指向 virtual function table 的指针(vptr),安插在每个 class object 内。
如果编译器对每个新产生的 class object 的 vptr 不能正确的设置初值,则会出错。因此,当编译器导入 vptr 到 class 中时,该 class 不再展现 bitwise semantics。而是合成一个 copy constructor 来使得 vptr 正确初始化,下面是个例子:
class ZooAnimal{ public: ZooAnimal(); virtual ~ZooAnimal(); virtual void animate(); virtual void draw(); private: ...//some data }; class Bear : public ZooAnimal{ public: Bear(); void animate(); void draw(); private: ...//some data };
ZooAnimal class object 以另一个 ZooAnimal class object 为初值,或 Bear class object 以另一个 Bear class object 为初值,都可以直接靠 bitwise copy semantics 完成。在这种情况下,vptr保持bitwise copy是安全的。
当一个 base class object 以其 derived class object 内容作初始化操作时,其 vptr 也需要保证安全:
Bear B; ZooAnimal Z = B;//sliced
显然,Z的 vptr 不应该指向 Bear 的 vtbl,也就是说,Base class 被合成出来的copy constructor会明确设定 object 的 vptr 指向 Base Class 的 vtbl,而非从 rhs 处执行 bitwise copy。