inside C++笔记之虚函数

i.单一继承下
例如如下类:
class Point { public: virtual ~Point(); virtual Point& mult( float ) = 0; float x() const { return _x; } virtual float y() const { return 0; } virtual float z() const { return 0; } protected: Point( float x = 0.0 ); float _x; }; class Point2d : public Point { public: Point2d( float x = 0.0, float y = 0.0 ) : Point( x ), _y( y ) {} ~Point2d(); // 重写基类虚函数 Point2d& mult( float ); float y() const { return _y; } protected: float _y; }; class Point3d: public Point2d { public: Point3d( float x = 0.0, float y = 0.0, float z = 0.0 ) : Point2d( x, y ), _z( z ) {} ~Point3d(); // 重写基类的虚函数 Point3d& mult( float ); float z() const { return _z; } protected: float _z; };
Virtual Table LayOut如图:
 inside C++笔记之虚函数_第1张图片
从Point到Point2d虚函数函数表的变化有三种可能
i. 它可以继承base class所声明的virtual function的函数实体,正确的说,是该函数实体的地址会被拷贝到derived class的virtual table 相对于的slot之中
ii. 它可以使用自己的函数实体,也就是改写了基类的虚函数,自己的函数实体地址必须放在对于的slot之中。
iii. 它可以加入一个新的virtual function。这个时候virtual table的尺寸会增大一个slot,而新的函数实体的地址被放到该slot之中。

从Point2d到Point3d函数表的变化也是一样的。


ii.多重继承
如下继承关系:

class Base1 { public: Base1(); virtual ~Base1(); virtual void speakClearly(); virtual Base1 *clone() const; protected: float data_Base1; }; class Base2 { public: Base2(); virtual ~Base2(); virtual void mumble(); virtual Base2 *clone() const; protected: float data_Base2; }; class Derived : public Base1, public Base2 { public: Derived(); virtual ~Derived(); virtual Derived *clone() const; protected: float data_Derived; };
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.虚继承
如下继承关系
class Point2d { public: Point2d( float = 0.0, float = 0.0 ); virtual ~Point2d(); virtual void mumble(); virtual float z(); protected: float _x, _y; }; class Point3d : public virtual Point2d public: Point3d( float = 0.0, float = 0.0, float = 0.0 ); ~Point3d(); float z(); protected: float _z; };

Virtual table layout如图:

inside C++笔记之虚函数_第2张图片

你可能感兴趣的:(C++,function,table,Class,float,destructor)