您的位置:首页 > 编程语言 > C语言/C++

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

2017-06-06 01:36 531 查看

深入探索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,一般而言扩充操作如下:

在memeber initialization list中的data members初始化操作会被放进constructor的函数里面,以member声明顺序为顺序。

如果有member没有出现在member initialization list当中,而这个member有一个default constructor的话那么该default constructor也必须被调用。

在那之前,如果class object有virtual table pointers,那么必须设定vptr的初值以指向正确的virtual tables

在那之前,所有上一层的base class constructor必须被调用,以base class的声明顺序为顺序。

在那之前,所有的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的执行算法如下:

在derived class constructor中,“所有virtual base classes”以及“上一层base class”的constructor会被调用

对象vptr会被初始化,指向相关的virtual tables

如果有member initialization list的话,将在constructor中扩展开来,这必须在vptr被设定之后,以免又一个virtual member function被调用。

最后执行程序员所提供的代码

对象复制语意学

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

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

当class内带一个member object,而其class有一个copy assignment operator时。

当一个class的base class有一个copy assignment operator时。

当一个class生命了任何virtual functions(这种情况下我们不能直接拷贝右端的object的vptr,因为后者可能是一个derived class object)

当class继承自一个virtual base class时。

析构语意学

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

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

destructor函数本体先被执行,也就是说vptr会在程序员的代码执行前被重设。

如果class拥有member class objects, 而后者拥有destructors, 那么它们会以其声明顺序的相反顺序被调用。

如果object内带一个vptr,那么首先重设相关的virtual table。

如果有任何直接的nonvirtual base classes拥有destructor,他们会以声明顺序的相反顺序被调用。

如果有任何virtual base classes拥有destructor,而当前讨论的这个class时最尾端(most-derived)的class,那么它们会以原来构造顺序的相反顺序被调用。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C++ 对象模型