c++多态深入分析--单继承
编译器在编译的时候,发现基类中有虚函数,此时编译器会为每个包含虚函数的类创建一个虚表(vtable),该表是一个一维数组,
在这个数组中存放每个虚函数地址,这张表解决了继承、覆盖的问题,保证其真实放映实际的函数。编译器会为基类与继承类都建
立一个虚表(即便继承类中没有virtual函数,但是基类中有,那么继承类也就是有)。一般编译器将指向虚表指针存放在实例对象
中第一个地址。那么其实我们只要获得这个类的实例对象的地址,就获得了指向该虚表的指针的地址。如图:

通过这段代码可以肯定结构如果所示,因为该对象的大小就是4,所以只有一个指针。
情况一:一般继承,无覆盖
由上图我们可以证明,不是虚函数的函数是绝对不会进入虚函数表的。去掉下面两行代码即可:
如果只是一般继承,没有发生覆盖,那么其结果如下图
情况二:一般继承有覆盖
class base{ public: vritual void first( ); virtual void second( );};void base::first( ){ std::cout<<"In base the first virtual function "<<std::endl;}void base::second( ){ std::cout<<"In base the second virtual function "<<std::endl;}class derived:public base{ public: void first( ); virtual void fourth( );};void derived::first( ){ std::cout<<"In derived the first function "<<std::endl;}void derived::fourth( ){ std::cout<<"In derived the fourth function"<<std::endl;}int main( ){ derived d; typedef void(*fun)(void); std::cout<<"vtptr address is"<<&d<<std::endl; std::cout<<"vt address is"<<(int *)*(int *)&d<<std::endl; f=(fun)*(int *)*(int *)&b; f( ); f=(fun)*( (int *)*(int *)&b + 1 ); f( ); f=(fun)*( (int *)*(int *)&b + 2 ); f( ); f=(fun)*( (int *)*(int *)&b + 3 ); f( ); return 0;}
结果如下
这个结果说明超出了虚表的地址范围,虚表里只有三个虚函数,所以同上的操作,去掉下面代码
那么我们就可以得到如下结构图虚表指针在什么时候和什么地方初始化呢?
在构造函数中进行虚表的创建和虚表指针的初始化。根据构造函数的调用顺序,在构造继承类构造函数时,先调用基类的构造函数,此时编译器只知道基类,并不知道后面继承类。它初始化基类对象的虚表指针,该虚表指针指向基类的虚表。当执行子类的构造函数时,子类对象的虚表指针被初始化,指向自身的虚表。
所以在在将各种继承类对象地址赋值给基类指针的时候,指向虚表的指针是不一样的,当调用其有覆盖的函数的时候,就能实现其多态效果。