虚函数

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>

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值