深入探索C++对象模型之五 --- 析构、构造、拷贝语意学

深入探索C++对象模型之五 — 析构、构造、拷贝语意学

一般而言,class的data member应该被初始化,并且只在constructor中或是在class的其它member functions中指定初值,其它任何操作都将破坏封装性质,使class的维护和修改更加困难。

纯虚函数

我们可以定义和调用一个pure virtual function:不过它只能被静态的调用,不能经由虚拟机制调用。

而对于pure virtual destructor,class设计者必须定义它。因为每一个derived class destructor都会被编译器加以扩展,以静态调用的方式调用其“每一个virtual base class”以及“上一层base class”的destructor。如果缺少任何一个base class destructor的定义,都会导致链接失败。

因此最好不要把virtual destructor声明为pure。

无继承情况下的对象构造

在C之中,全局性的定义被视为一个“临时性的定义”,因为它没有明确的初始化操作。一个“临时性的定义”可以在程序中发生多次,那些实例会被链接器折叠起来,只留下一个单独实体,被放在data segment中的BSS段中。而C++不支持“临时性定义”,C++中所有全局对象都被当作“初始化过的数据”来对待。

如果要对class中的所有成员都设定常量初值,那么给予一个explicit initialization list会比较高效。

Explicit Initialization list 带来三项缺点:
1. 只有当class members都是public时,此法才有效。
2. 只能指定常量,因此它们在编译时期就可以被评估求值。
3. 由于编译器没有自动施行,所以初始化行为的失败可能性会比较高一些。

继承体系下的对象构造

编译器会扩充每一个constructor,一般而言扩充操作如下:

  1. 在memeber initialization list中的data members初始化操作会被放进constructor的函数里面,以member声明顺序为顺序。
  2. 如果有member没有出现在member initialization list当中,而这个member有一个default constructor的话那么该default constructor也必须被调用。
  3. 在那之前,如果class object有virtual table pointers,那么必须设定vptr的初值以指向正确的virtual tables
  4. 在那之前,所有上一层的base class constructor必须被调用,以base class的声明顺序为顺序。
  5. 在那之前,所有的virtual base class constructors必须被调用,从左到右,从最深到最浅。
虚拟继承

虚拟继承中因为“base class subobject”共享性之故,那么在继承体系中间层面的class一定不能调用virtual base class的constructor,取而代之的是,作为最底层的class来负责完成“被共享之virtual base subobject”的构造。

那么编译器是如何实现上述行为的呢?我们注意到,“virtual base calss constructor被调用”有着明确的定义,即只有当一个完整的class object被定义出来的时候,它才会被调用;如果object只是某个完整object的subobject的话那么它就不会被调用

vptr的初始化

在一个class的constructor中,经由构造中的对象来调用一个virtual function,其函数实体应该是在此class中有作用的那个。为了能够找到正确的virtual function, 必须在合适的时机来初始化vptr的内容。
通常constructor的执行算法如下:

  1. 在derived class constructor中,“所有virtual base classes”以及“上一层base class”的constructor会被调用
  2. 对象vptr会被初始化,指向相关的virtual tables
  3. 如果有member initialization list的话,将在constructor中扩展开来,这必须在vptr被设定之后,以免又一个virtual member function被调用。
  4. 最后执行程序员所提供的代码
对象复制语意学

当以一个class object 指定另一个class object的时候,如果class没有表现出bitwise copy的话,那么编译器就自动合成一个copy asssignment operator。

class在以下情况不会表现出bitwise语意:

  1. 当class内带一个member object,而其class有一个copy assignment operator时。
  2. 当一个class的base class有一个copy assignment operator时。
  3. 当一个class生命了任何virtual functions(这种情况下我们不能直接拷贝右端的object的vptr,因为后者可能是一个derived class object)
  4. 当class继承自一个virtual base class时。
析构语意学

如果class没有定义destructor,那么只有在class内袋的member object或者自己的base class拥有destructor的情况下,编译器才会自动合成一个出来。

编译器通过合成一个destructor,来保证调用base class destructor,如果class的设计者定义了一个destructor,那么编译器也会扩展它。扩展方式和constructor被扩展的方式顺序相反:

  1. destructor函数本体先被执行,也就是说vptr会在程序员的代码执行前被重设。
  2. 如果class拥有member class objects, 而后者拥有destructors, 那么它们会以其声明顺序的相反顺序被调用。
  3. 如果object内带一个vptr,那么首先重设相关的virtual table。
  4. 如果有任何直接的nonvirtual base classes拥有destructor,他们会以声明顺序的相反顺序被调用。
  5. 如果有任何virtual base classes拥有destructor,而当前讨论的这个class时最尾端(most-derived)的class,那么它们会以原来构造顺序的相反顺序被调用。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值