虚函数

来源:互联网 发布:飞歌导航端口 编辑:程序博客网 时间:2024/05/17 23:27

1、虚函数

·虚函数表(vftable)是怎么实现的?虚函数表存放在哪里?

·虚函数表中的数据是在什么时候确定的?

·对象中的虚函数表指针(vfptr)又在什么时候赋值的?

编译器会为拥有虚函数的类创建一个虚函数表,且这个虚函数表存放在类定义模块的数据段中。模块的数据段通常存放定义在该模块的全局数据和静态数据,这样我们可以把虚函数表看作是模块的全局数据或者静态数据。

类的虚函数表会被这个类的所有对象所共享。类的对象可以有很多,但是他们的虚函数表指针都指向同一个虚函数表。因此,我们可以把虚函数表简单理解为类的静态数据成员。值得注意的是,虽然虚函数表是共享的,但是虚函数表指针并不是,类的每一个对象有一个属于它自己的虚函数表指针。虚函数表中存放的是虚函数的地址。

 

虚函数表的地址(即vfptr)被存放在对象的起始位置。 同时,虚函数表指针的初始化发生在构造函数的调用过程中, 但是在执行构造函数体之前,即进入到构造函数的"{"和"}"之前。 为了更好的理解这一问题, 我们可以把构造函数的调用过程细分为两个阶段,即:

1)进入到构造函数体之前。在这个阶段如果存在虚函数的话,虚函数表指针被初始化。如果存在构造函数的初始化列表的话,初始化列表也会被执行。

2)进入到构造函数体内。这一阶段是我们通常意义上说的构造函数

 

2、虚函数实例说明

<span style="font-family:SimSun;font-size:18px;">1)单个类中存在虚函数:class Base{public:Base(int aa, int bb): a(aa), b(bb){fun();}virtual void fun(){cout<<"Base"<<a<<endl;}int a;const int b;};类结构如下:1>  class Basesize(12):1>  +---1>   0| {vfptr}1>   4| a1>   8| b1>  +---1>  1>  Base::$vftable@:1>  | &Base_meta1>  |  01>   0| &Base::fun2)单继承中的虚函数:class Base{public:Base(int aa, int bb): a(aa), b(bb){fun();}virtual void fun(){cout<<"Base"<<a<<endl;}int a;const int b;};class Derived: public Base{public:Derived(int aa, int bb): Base(aa, bb){fun();}void fun(){cout<<"Derived"<<a<<endl;}virtual void nonvirtualF(){}int c;};类结构如下:1>  class Basesize(12):1>  +---1>   0| {vfptr}1>   4| a1>   8| b1>  +---1>  1>  Base::$vftable@:1>  | &Base_meta1>  |  01>   0| &Base::fun1> 1>  class Derivedsize(16):1>  +---1>  | +--- (base class Base)1>   0| | {vfptr}1>   4| | a1>   8| | b1>  | +---1>  12| c1>  +---1>  1>  Derived::$vftable@:1>  | &Derived_meta1>  |  01>   0| &Derived::fun  //覆盖了Base::fun1>   1| &Derived::nonvirtualF3)多继承中的虚函数class Base{public:Base(int aa, int bb): a(aa), b(bb){fun();}virtual void fun(){cout<<"Base"<<a<<endl;}int a;const int b;};class Derived: public Base{public:Derived(int aa, int bb): Base(aa, bb){fun();}void fun(){cout<<"Derived"<<a<<endl;}virtual void nonvirtualF(){}int c;};class SubDrived: public Derived, public Base{public:SubDrived(int aa, int bb):Base(aa, bb), Derived(aa, bb){}virtual void SubDrivedF(){}virtual void SubDrivedFF(){}virtual void SubDrivedFFF(){}int d;};类结构如下:1>  class Basesize(12):1>  +---1>   0| {vfptr}1>   4| a1>   8| b1>  +---1>  1>  Base::$vftable@:1>  | &Base_meta1>  |  01>   0| &Base::fun1>  1>  class Derivedsize(16):1>  +---1>  | +--- (base class Base)1>   0| | {vfptr}1>   4| | a1>   8| | b1>  | +---1>  12| c1>  +---1>  1>  Derived::$vftable@:1>  | &Derived_meta1>  |  01>   0| &Derived::fun1>   1| &Derived::nonvirtualF1>  1>  class SubDrivedsize(32):1>  +---1>  | +--- (base class Derived)1>  | | +--- (base class Base)  //Derived中包含的Base类1>   0| | | {vfptr}1>   4| | | a1>   8| | | b1>  | | +---1>  12| | c1>  | +---1>  | +--- (base class Base)//SubDerived继承的Base类1>  16| | {vfptr}1>  20| | a1>  24| | b1>  | +---1>  28| d1>  +---1>  1>  SubDrived::$vftable@Derived@: //SubDerived中有两个vfptr指向两个基类的vftable1>  | &SubDrived_meta1>  |  01>   0| &Derived::fun1>   1| &Derived::nonvirtualF1>   2| &SubDrived::SubDrivedF//该类中的虚函数地址位于声明的第一个基类的虚函数表的后面1>   3| &SubDrived::SubDrivedFF1>   4| &SubDrived::SubDrivedFFF1>  1>  SubDrived::$vftable@Base@:1>  | -161>   0| &Base::fun</span>

 

0 0