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中做出仲裁。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值