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 Base size(12):
1> +---
1> 0 | {vfptr}
1> 4 | a
1> 8 | b
1> +---
1>
1> Base::$vftable@:
1> | &Base_meta
1> | 0
1> 0 | &Base::fun
2)单继承中的虚函数:
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 Base size(12):
1> +---
1> 0 | {vfptr}
1> 4 | a
1> 8 | b
1> +---
1>
1> Base::$vftable@:
1> | &Base_meta
1> | 0
1> 0 | &Base::fun
1>
1> class Derived size(16):
1> +---
1> | +--- (base class Base)
1> 0 | | {vfptr}
1> 4 | | a
1> 8 | | b
1> | +---
1> 12 | c
1> +---
1>
1> Derived::$vftable@:
1> | &Derived_meta
1> | 0
1> 0 | &Derived::fun //覆盖了Base::fun
1> 1 | &Derived::nonvirtualF
3)多继承中的虚函数
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 Base size(12):
1> +---
1> 0 | {vfptr}
1> 4 | a
1> 8 | b
1> +---
1>
1> Base::$vftable@:
1> | &Base_meta
1> | 0
1> 0 | &Base::fun
1>
1> class Derived size(16):
1> +---
1> | +--- (base class Base)
1> 0 | | {vfptr}
1> 4 | | a
1> 8 | | b
1> | +---
1> 12 | c
1> +---
1>
1> Derived::$vftable@:
1> | &Derived_meta
1> | 0
1> 0 | &Derived::fun
1> 1 | &Derived::nonvirtualF
1>
1> class SubDrived size(32):
1> +---
1> | +--- (base class Derived)
1> | | +--- (base class Base) //Derived中包含的Base类
1> 0 | | | {vfptr}
1> 4 | | | a
1> 8 | | | b
1> | | +---
1> 12 | | c
1> | +---
1> | +--- (base class Base)//SubDerived继承的Base类
1> 16 | | {vfptr}
1> 20 | | a
1> 24 | | b
1> | +---
1> 28 | d
1> +---
1>
1> SubDrived::$vftable@Derived@: //SubDerived中有两个vfptr指向两个基类的vftable
1> | &SubDrived_meta
1> | 0
1> 0 | &Derived::fun
1> 1 | &Derived::nonvirtualF
1> 2 | &SubDrived::SubDrivedF//该类中的虚函数地址位于声明的第一个基类的虚函数表的后面
1> 3 | &SubDrived::SubDrivedFF
1> 4 | &SubDrived::SubDrivedFFF
1>
1> SubDrived::$vftable@Base@:
1> | -16
1> 0 | &Base::fun
</span>