i.单一继承下
例如如下类:
Virtual Table LayOut如图:
从Point到Point2d虚函数函数表的变化有三种可能
i. 它可以继承base class所声明的virtual function的函数实体,正确的说,是该函数实体的地址会被拷贝到derived class的virtual table 相对于的slot之中
ii. 它可以使用自己的函数实体,也就是改写了基类的虚函数,自己的函数实体地址必须放在对于的slot之中。
iii. 它可以加入一个新的virtual function。这个时候virtual table的尺寸会增大一个slot,而新的函数实体的地址被放到该slot之中。
从Point2d到Point3d函数表的变化也是一样的。
ii.多重继承
如下继承关系:
Derived支持virtual function的困难度,在于Base2的身上,以此为例,分别是(1)virtual destructor,(2),被继承下来的Base2::mumble(),(3),一组clone()函数实体。这个稍后再说。
在多重继承下,一个derived class内含n-1个额外的virtual tables,n表示其上一场base classes的数目,单一继承不会有额外的virtual table,对于本例而言,会有两个
1. 一个主要实体,与Base1(最左端的base class)共享
2. 一个次要实体,与Base2(第二个base class)有关
针对每一个virtual tables,Derived 对象中有对应的vptr。Vptrs在构造函数中被设立初值。
如图所示:
现在要解决开始的三个问题。
第一种:
Base2* ptr = new Derived; delete ptr;
通过第二种或更后继的指针调用Derived的析构函数,这时要调整ptr的位置到Derived的开始处。
第二种:
Derived *ptr = new Derived; ptr->mumble();
Derived指针调用第二个或更后继的基类的虚函数,这时要调整ptr的位置到Base2的位置处。
第三种:
Base2* ba1 = new Derived; Base2* ba2 = ba1->clone();
Ba1->clone()返回的函数指针是指向Derived的起始位置,这时要调整指针到Base2的位置,才能正确的初始化ba2。
iii.虚继承
如下继承关系
Virtual table layout如图: