Copy Constructor 的构造操作

以一个object的内容作为另一个class object的初值的三种情况:

  1. 对一个object做显式的初始化操作; class X{};X x; X xx = x;
  2. 当object被当做参数交给某个函数 extern void foo(X x); void bar() { X xx; foo(xx);…}
  3. 当函数传回一个class object时 X foo_bar() {X xx; …return xx;}

如果class没有提供一个explicit copy constructor又当如何?当class object以“相同class的另一个object”作为初值,其内部是以所谓的default memberwise initialization手法完成。
Default Memberwise Initiazation: 把每一个内建的或派生的data member(例如一个指针或一个数组)的值,从某个object拷贝一份到另一个object身上。不过它并不会拷贝其中的member class object,而是以递归的方式施行memberwise initialization。
什么时候一个class不展现出“bitwise copy semantics”呢?(需要编译器合成)
有4种情况:

  1. 当class内含一个member object而后者的class声明一个copy constructor时(不论是被class设计者显示地声明,就像前面的String那样;或是被编译器合成,像class Word那样)。
  2. 当class继承自一个base class而后者存在一个copy constructor时(再次强调,不论是被显式声明或是被合成而得);
  3. 当class声明了一个或多个virtual functions时;
  4. 当class派生自一个继承串链,其中有一个或多个virtual base classes时。

重新设定Virtual Table的指针(第三种情况)
当class声明了一个或多个virtual functions时,编译期间的两个程序扩张操作:
a. 增加一个virtual function table(vtbl),内含每一个有作用的virtual function的地址;
b. 一个指向virtual function table的指针(vptr),安插在每一个class object内。
当编译器导入一个vptr到class之中时,该class就不再展现bitwise semantics了。现在,编译器需要合成出一个copy constructor以求将vptr适当地初始化,下面是个例子:

class ZooAnimal {
public:
    ZooAnimal();
    virtual ~ZooAnimal();
    virtual void animate();
    virtual void draw();
    //...
private:
    // ZooAnimal的 animate()和draw()所需要的数据
};
class Bear : public ZooAnimal{
public:
    Bear();
    void animate();
    void draw();
    virtual void dance();
 private:
    // Bear 的 animate()、draw()和dance()所需要的数据
};
Bear yogi; // default Bear constructor初始化, yogi的vptr被设定指向Bear class的virtual table (靠编译器安插的代码完成)
Bear winnie = yogi; // 把yogi的vptr值拷贝给Winnie的vptr是安全的

在这里插入图片描述

ZooAnimal class object以另一个ZooAnimal class object作为初值,或Bear class object以另一个Bear class object作为初值,都可以直接靠“bitwise copy semantics”完成(除了可能会有pointer member之外。为了简化,这种情况被我革除)。

当一个base class object以其derived class的object内容做初始化操作时,其vptr复制操作也必须保证安全,例如:
ZooAnimal franny = yogi; //这会发生切割sliced 行为

franny的vptr不可以被设定指向Bear class 的virtual table(但如果yogi的vptr被直接“bitwise copy”的话,就会导致此结果),否则当下面程序片段中的draw()被调用而franny被传进去时,就会“炸毁”:

void draw(const ZooAnimal& zoey)
{
    zoey.draw();
}
void foo() 
{
    // franny的vptr指向ZooAnimal的virtual table,而非Bear的virtual table(它由yogi的vptr指出)
    ZooAnimal franny = yogi;
    
    draw(yogi); // 调用Bear::draw()
    draw(franny); // 调用ZooAnimal::draw()
}

在这里插入图片描述

处理Virtual Base Class Suboject(第四种情况)
Virtual Base Class 的存在需要特别处理。一个class object如果以另一个object作为初值,而后者有一个virtual base class suboject,那么也会使“bitwise copy semantics”失效。
每一个编译器对于虚拟继承的支持承诺,都代表必须让“derived class object 中的virtual base class suboject位置”在执行期准备妥当。维护“位置的完整性”是编译器的责任。“Bitwise copy semantics”可能会破坏这个位置,所以编译器必须在它自己合成出来的copy constructor中做出仲裁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值