文章目录
- 一个虚基类子对象只会在派生类中存在一份实例,不管它在class继承体系中出现了多少次。
3.1 Data Member 数据绑定
早期C++的两种防御性程序设计风格
- 把所有的数据成员放在类的声明起头处以确保正确绑定
- 把所有的内联函数,不管大小都放在类声明之外。
-------------------------------------------------------------------------------------------------------------------------------------------
- 对于成员函数本体的分析,会直到整个类声明都出现了才开始,因此在一个内联函数躯体之内的一个数据成员绑定操作,会在整个类声明完成之后才发生
- 然而这对成员函数的实参列表并不为真,实参列表中的名称还是会在它们第一次遭遇时被适当的决议。
3.2 Data Member 的布局
- 非静态数据成员在类对象中的排列顺序和其被声明的顺序一样,任何中间介入的静态数据成员都不会被放进对象布局之中。
- 在同一个access section 中,members的排列只需符合较晚出现的members在类对象中有较高地址即可。多个access section之中的data members自由排列,不必在乎它们出现在class声明中的顺序。
3.3 Data Member 的存取
静态数据成员
- 若取一个静态数据成员的地址,会得到一个指向其数据类型的指针,而不是一个指向其class member的指针,因为静态数据成员并不在一个类对象之中。
- 若两个类当中的静态数据成员的名称一样,编译器会对每一个静态数据成员编码,以获得一个独一无二的程序识别代码。
非静态数据成员
- 非静态数据成员直接存放在每一个类对象之中,除非经由显示的或隐式的类对象,否则没有办法直接存取它们。
- 欲对一个非静态数据成员进行存取操作,编译器需要把class object 的起始地址加上data member的偏移位置。
- 每一个非静态数据成员的偏移位置在编译时期即可获知,甚至如果成员属于一个基类子对象(派生自单一或者继承串联)也是一样的。
- 存取一个非静态数据成员,其效率和存取一个C struct member 或一个非派生的成员的数据是一样的。
- 虚拟继承将为经由基类子对象存取一个类的数据成员导入一层新的间接性。
3.4 继承 与 Data Member
只要继承不要多态
- 具体继承相对于虚拟继承并不会增加空间或存取时间上的额外负担。
- 把原本两个不相关的classes凑成一对“type/subtype”并带有继承关系,会有什么易犯的错误呢?
- 可能会设计一些相同操作函数
- 可能为了表现类体系之抽象化而膨胀所需的空间。
加上多态
- 导入一个和对象有关的虚表,用来存放他所声明的每一个虚函数的地址。
- 在每一个对象中导入一个vptr,执行执行期的链接,使每一个对象能找到相对于的虚表
- 加强constructors,使它能够为vptr设定初值,让它指向class所对应的虚表。
- 加强destructor,使它能够磨削指向类之相关的虚表的vptr。
- 把vptr放在尾端,可以保留base class C struct 的对象布局,因而允许在C程序代码中也能够使用
- 把vptr放在类对象前端,对于在多重继承之下,通过指向class members的指针调用虚函数会带来一些帮助。
多重继承
- 对于一个多重派生对象,将其地址指定给最左端基类的指针,情况将和单一继承时相同,因为两者都指向相同的起始地址。
- 至于第二个或后继的base class 的地址指定操作,则需要将地址修改过:加上(或减去,如果downcast的化)介于中间的基类子对象的大小。
虚拟继承
-
类如果内含一个或多个虚拟基类子对象,将被分割为两个部分:一个不变区域和一个共享区域
-
不变区域中的数据,不管后继如何变化总是拥有固定的偏移量,所以这一部分的数据可以直接存取。
-
共享区域,所表现的就是虚拟基类子对象,这一部分的数据,其位置会因为每次的派生操作而有所变化,所以它们只可以被间接存取。
------------------------------------------------------------------------------------------------------------------------------------------- -
存取类的共享部分:在每一个派生类对象中安插一些指针,每个指针指向一个虚拟基类。要存取继承得来的虚拟基类成员,可以通过相关指针间接完成。
------------------------------------------------------------------------------------------------------------------------------------------- -
每一个对象必须针对其每一个虚拟基类背负一个额外的指针,如何才能让类有固定的负担,不因其虚拟基类的个数而有所变化?
- 类对象安排一个指针,指向虚拟基类表
- 虚拟函数表中放置虚拟基类的偏移量。
-
经由一个非多态的类对象,存取一个继承而来的虚拟基类的成员,可以被优化为一个直接存取操作。