============================================================================
3-0. 类所占的内存大小受到三个因素的影响:
(1)语言自己所形成的额外负担(Virtual base classes);
(2)编译器对于特殊状况所提供的优化处理(空基类优化);
(3)Alignment的限制(对齐);
注:Empty Virtual base class提供一个Virtual interface,没有定义任何数据,某些编译器对此提供了特殊处理(优化):一个empty virtual base class被视为derived class object最开头的一部分,也就是说它并无花费任何额外空间。程序员
============================================================================函数
3-1. Data Member 的绑定
member rewriting rule:一个inline函数实体以内,在整个class 声明未被彻底看见以前,是不会被评估求值的。也即:布局
extern int x; class Point3d { public: // 对于函数自己的分析将延迟直至class声明的右大括号出现才开始 float X() const { return x; } private: float x; }; // 事实上,分析在这里进行
对member functions自己的分析,会直到整个class的声明都出现了才开始。所以,在一个inline member function躯体以内的一个data member 绑定操做,会在整个class声明完成以后才发生(这就保证取用到的变量是 data member 而不是 global )。优化
可是对于argument list(函数参数列),仍是会在他们第一次遇到时被适当地决议完成。this
============================================================================
3-2. Data Member 的布局
Nonstatic data members 的class object 中的排列顺序将和其被声明的顺序同样,任何中间介入的static data members 都不会被放进对象布局之中。spa
============================================================================3d
3-3. Data Member 的存取
(1)Static Data Members:被编译器提出于class以外,并被视为一个global变量(但只在class生命范围以内可见),其不会致使任何空间上或执行时间上的额外负担。每个Static Data Members只有一个实体,存放在程序的data segment之中,每次程序取用static member,就会被内部转化为对该惟一的extern实体的直接取用操做。指针
(2)Nonstatic Data Members
Nonstatic Data Members:直接存放在每个class object之中,除非经由明确的(explicit)或暗喻的(inplicit)class object,没有办法直接存取它们。只要程序员在一个member function中直接处理一个Nonstatic Data Members,所谓“implicit class object”(this指针)就会发生。
每个Nonstatic Data Members的偏移量(offset)在编译时期便可获知,甚至member属于一个base class subobject(派生自单一或多重继承串链)也是同样。所以,存取一个Nonstatic Data Members,其效率和存取一个C struct member或一个nonderived class 的 member是同样的。code
注:经由对象(object)和经由ptr取用成员x,若是成员member是从一个Virtual base class继承而来时,ptr存取操做会延迟至执行期。而经由object的取用操做,members的offset位置在编译时期就固定了。对象
============================================================================
3-4. “继承”与 Data Member
(1)只要继承不要多态
(2)加上多态
注:a. 单一继承提供了一种“天然多态”形式,是关于classes 体系中的base type 和 derived type之间的转换。base class 和 derived class 的objects都是从相同的地址开始,其间差别只在于 derived object 比较大,用以容纳它本身的nonstatic data members。
b. 当把vptr放在class object 的起始处,若是base class 没有virtual function 而derived class 有(如书 图3.2b),那么单一继承的天然多态就会被打破。在这种状况下,把一个derived object 转换为其base 类型,就须要编译器介入,用以调整地址(因vptr插入之故)。在既是多重继承又是虚拟继承的状况下,编译器的介入更有必要。
(3)多重继承
(4)虚拟继承
《深度探索C++对象模型》中介绍了3种实现模型。这里只说一下第3种:是在Virtual function table(虚函数表)中放置 Virtual base class 的offset(而不是地址),图3.5b 显示这种base class offset 实现模型。至此,Virtual function table 可经由正值或负值来索引。若是是正值,很显然就是索引到Virtual functions;若是是负值,则是索引到Virtual base class offset。
注:通常而言,Virtual base class 最有效的一种运用形式就是:一个抽象的Virtual base class ,没有任何data members。
============================================================================
3-6. 指向Data Members 的指针
详细调查class members 的底层布局,可用以决定vptr是放在class的起始处或是尾端。也能够用来决定class 中的access sections 的次序。
假设类有3个float成员,若是vptr放在对象的尾端,则3个成员的offset(& Class::object1)分别是0,4,8. 若是vptr放在对象的起头,则3个成员在对象布局中的offset分别是4,8,12. 然而你若去取data members的地址,传回的值老是多1. 也就是1,59或者5,9,13等等。之因此这样,缘由以下:
多重继承下,状况会有所不一样:
============================================================================