《深度探索C++对象模型》读书笔记

来源:互联网 发布:golang os.exit 编辑:程序博客网 时间:2024/06/05 13:10

         1,  在Stroustrup当初设计的C++对象模型中,Nonstatic data members被配置于每一个class object之内,static data members则被存放在所有的class object之外。Static和nonstatic function members也被放在所有的class object之外,Virtual functions则以两个步骤支持之:

         (1)每一个class产生出一堆指向virtual functions的指针,放在表格之中,这个表格被称为virtual table(vtbl)。          

   (2)每一个class object被添加了一个指针,指向相关的virtual table.通常这个指针被称为vptr.vptr的设定(setting)和重置(resetting)都由每一个class的constructor、destructor和copy assignment运算符自动完成。每一个class所关联的type_info object(用以支持runtime type identification,RTTI)也经由virtual table被指出来,通常是放在表格的第一个slot处。

         2, 一个指向类的指针与一个指向整数的指针或一个指向template Array的指针之间的差异既不在其指针表示法不同,也不在于其内容(代表一个地址)不同,而是在其所寻址出来的object类型不同。

          3, Bear b;
ZooAnimal za = b;  // 这会引起切割(sliced)
// 调用 ZooAnimal::rotate()
za.rotate();

为什么rotate所调用的是ZooAnimal实体而不是Bear实体?此外,如果初始化函数(应用于上述assignment操作发生时)将一个object内容完整拷贝到另一个object中去,为什么za的vptr不指向Bear的virtual table? 

   第二个问题的答案是,编译器在(1)初始化及(2)指定(assignment)操作之间做出了仲裁。编译器必须确保如果某个object含有一个或一个以上的vptrs,那些vptrs的内容不会被base class object初始化或改变。

4,default constructor仅在编译器需要它时,才会被合成出来。

   通常来说,由编译器合成出来的default constructor是没啥用的(trivial),但有以下几种例外:

(1)带有“Default Constructor”的Member Class Object(带其他类成员的类)

(2)“带有Default Constructor”的Base Class

  (3)“带有一个Virtual Function”的Class    

 下面两个扩张操作会在编译期间发生:

   1.一个virtual function table会被编译器产生出来,内放class的virtual functions地址;

   2.在每一个class object中,一个额外的pointer member(也就是vptr)会被编译器合成出来,内含相关的class vtbl的地址。

(4)“带有一个virtual Base Class”的Class


5,  一个class不展现出“bitwise copy semantics”的四种情况:

(1)当class内含一个member object而后者的class声明有一个copy constructor时(无论是被明确声明或被合成而得)

 (2)当class继承自一个base class而后者存在有一个copy constructor时

 (3)当class声明了一个或多个virtual functions时

 (4)当class派生自一个继承串链,其中有一个或多个virtual base 


6,  ***成员的初始化队伍***

   下列情况中,为了让你的程序能够被顺利编译,你必须使用member initialization list:

   (1)当初始化一个reference member时;

   (2)当初始化一个const member时;

   (3)当调用一个base class的constructor,而它拥有一组参数时;

   (4)当调用一个member class的constructor,而它拥有一组参数时。

7,class X {};
class Y : public virtual X {};
class Z : public virtual X {};
class A : public Y,public Z {};

得出的结果也许会令你毫无头绪

 sizeof(X): 1
sizeof(Y): 4
sizeof(Z): 4
sizeof(A): 8

   下面一一阐释原因:

   (1)对于一个class X这样的空的class,由于需要使得这个class的两个objects得以在内存中配置独一无二的地址,故编译器会在其中安插进一个char.因而class X的大小为1.

   (2)由于class Y虚拟继承于class X,而在derived class中,会包含指向visual base class subobject的指针(4 bytes),而由于需要区分这个class的不同对象,因而virtual base class X subobject的1 bytes也出现在class Y中(1 bytes),此外由于Alignment的限制,class Y必须填补3bytes(3 bytes),这样一来,class Y的大小为8.

 (3)不管它在class继承体系中出现了多少次,一个virtual base class subobject只会在derived class中存在一份实体。因此,class A的大小有以下几点决定:(a)被大家共享的唯一一个class X实体(1 byte);(b)Base class Y的大小,减去“因virtual base class X而配置”的大小,结果是4 bytes.Base class Z的算法亦同。(8bytes)(c)classs A的alignment数量,前述总和为9 bytes,需要填补3 bytes,结果是12 bytes.