【20090821】C++培训日记-虚函数表
检测方法(VS2005):项目命令行加上参数/d1reportAllClassLayout,在编译时CTRL+F5搜索输出,查看类的对象布局。
vftable - 虚函数表; vbtable - 虚继承的父类表; member - 类的成员变量(这个只是写作方便说明 = =)。
总结:
- 继承方式:非virtual继承:导入各个父类的结构(按照父类声明的顺序,从上到下),自身member在最后
- 重写virtual方法:更新该方法最早定义的类的vftable
- 新的virtual方法:在最左父类的vftable增加
- 继承方式:有virtual继承:在自身member后增加virtual父类的结构(按照子类继承的顺序从左到右),同时在最前面增加vbtable(如果没有的话),增加一项指向父类结构
- 重写virtual方法:更新该方法的最早定义的类的vftable
- 新的virtual方法:在自身最前面增加vftable(如果没有的话),在自己的vftable增加
CBase:持有一个virtual方法和一个成员变量,因此结构只有{vftable}和member,其中{vftable}只有一项:CBase::fun()。
{
public:
virtual void fun(void) { }
public:
int base;
};
1> +---
1> 0 | {vfptr}
1> 4 | base
1> +---
1>CBase::$vftable@:
1> | &CBase_meta
1> | 0
1> 0 | &CBase::fun
1>CBase::fun this adjustor: 0
CDerived:非virtual继承CBase,持有一个virtual重写方法和一个virtual新方法,一个成员变量,因此结构为 CBase结构(vftable@CBase, member@CBase),以及自身member。其中vftable@CBase的CBase::fun项在这里更新为CDerived::fun,同时增加了一项CDerived::vfun。
{
public:
void fun(void) { }
virtual void vfun(void) { }
public:
int derived;
};
1> +---
1> | +--- (base class CBase)
1> 0 | | {vfptr}
1> 4 | | base
1> | +---
1> 8 | derived
1> +---
1>CDerived::$vftable@:
1> | &CDerived_meta
1> | 0
1> 0 | &CDerived::fun
1> 1 | &CDerived::vfun
1>CDerived::fun this adjustor: 0
1>CDerived::vfun this adjustor: 0
CDerived2:virtual继承CBase,持有一个virtual重写方法和一个virtual新方法,一个成员变量,因此结构为vftable@自身,vbtable@自身,member@自身,以及CBase结构。其中vftable@自身只有一项:CDerived2::vfun(),vbtable@自身只有一项:它virtual继承的父类CBase,而vftable@CBase原来的CBase::fun更新为CDerived2::fun。
{
public:
void fun(void) { }
virtual void vfun(void) { }
public:
int derived2;
};
1> +---
1> 0 | {vfptr}
1> 4 | {vbptr}
1> 8 | derived2
1> +---
1> +--- (virtual base CBase)
1>12 | {vfptr}
1>16 | base
1> +---
1>CDerived2::$vftable@CDerived2@:
1> | &CDerived2_meta
1> | 0
1> 0 | &CDerived2::vfun
1>CDerived2::$vbtable@:
1> 0 | -4
1> 1 | 8 (CDerived2d(CDerived2+4)CBase)
1>CDerived2::$vftable@CBase@:
1> | -12
1> 0 | &CDerived2::fun
1>CDerived2::fun this adjustor: 12
1>CDerived2::vfun this adjustor: 0
1>vbi: class offset o.vbptr o.vbte fVtorDisp
1> CBase 12 4 4 0
CDerived3:virtual继承CBase,因此结构为vbtable@自身,member@自身,CBase结构。vbtable@自身只有一项指向CBase结构。
{
public:
void fun(void) { }
public:
int derived3;
};
1> +---
1> 0 | {vbptr}
1> 4 | derived3
1> +---
1> +--- (virtual base CBase)
1> 8 | {vfptr}
1>12 | base
1> +---
1>CDerived3::$vbtable@:
1> 0 | 0
1> 1 | 8 (CDerived3d(CDerived3+0)CBase)
1>CDerived3::$vftable@:
1> | -8
1> 0 | &CDerived3::fun
1>CDerived3::fun this adjustor: 8
1>vbi: class offset o.vbptr o.vbte fVtorDisp
1> CBase 8 0 4 0
CGDerived:继承CDerived2、CDerived3,因此首先是CDerived2的结构和CDerived3的结构,自己的新virtual方法vgfun则添加在最左父类CDerived2的虚函数表中。然后是自己的成员。最后,CDerived2和CDerived3的父类CBase结构也带入其中。它的fun默认指向CGDerived的最左父类CDerived2::fun。
{
public:
void vfun() { }
virtual void vgfun() { }
public:
int gd;
};
1> +---
1> | +--- (base class CDerived2)
1> 0 | | {vfptr}
1> 4 | | {vbptr}
1> 8 | | derived2
1> | +---
1> | +--- (base class CDerived3)
1>12 | | {vbptr}
1>16 | | derived3
1> | +---
1>20 | gd
1> +---
1> +--- (virtual base CBase)
1>24 | {vfptr}
1>28 | base
1> +---
1>CGDerived::$vftable@CDerived2@:
1> | &CGDerived_meta
1> | 0
1> 0 | &CGDerived::vfun
1> 1 | &CGDerived::vgfun
1>CGDerived::$vbtable@CDerived2@:
1> 0 | -4
1> 1 | 20 (CGDerivedd(CDerived2+4)CBase)
1>CGDerived::$vbtable@CDerived3@:
1> 0 | 0
1> 1 | 12 (CGDerivedd(CDerived3+0)CBase)
1>CGDerived::$vftable@CBase@:
1> | -24
1> 0 | &thunk: this-=12; goto CDerived2::fun
1>CGDerived::vfun this adjustor: 0
1>CGDerived::vgfun this adjustor: 0
1>vbi: class offset o.vbptr o.vbte fVtorDisp
1> CBase 24 4 4 0
CGG:继承CGDerived,增加一个变量,基本只是把CGDerived的结构再套一层,最后加上自己的成员变量。vbtable所指向的父类结构依然在最后。
{
public:
int kc;
};
1> +---
1> | +--- (base class CGDerived)
1> | | +--- (base class CDerived2)
1> 0 | | | {vfptr}
1> 4 | | | {vbptr}
1> 8 | | | derived2
1> | | +---
1> | | +--- (base class CDerived3)
1>12 | | | {vbptr}
1>16 | | | derived3
1> | | +---
1>20 | | gd
1> | +---
1>24 | kc
1> +---
1> +--- (virtual base CBase)
1>28 | {vfptr}
1>32 | base
1> +---
1>CGG::$vftable@CDerived2@:
1> | &CGG_meta
1> | 0
1> 0 | &CGDerived::vfun
1> 1 | &CGDerived::vgfun
1>CGG::$vbtable@CDerived2@:
1> 0 | -4
1> 1 | 24 (CGGd(CDerived2+4)CBase)
1>CGG::$vbtable@CDerived3@:
1> 0 | 0
1> 1 | 16 (CGGd(CDerived3+0)CBase)
1>CGG::$vftable@CBase@:
1> | -28
1> 0 | &thunk: this-=16; goto CDerived2::fun
1>vbi: class offset o.vbptr o.vbte fVtorDisp
1> CBase 28 4 4 0
CBase2:空类默认都有一个占位,size为1
{
};
1> +---
1> +---
CD2:virtual继承则一定会创建vbtable,用vbptr指针指向,因此size为4。
{
};
1> +---
1> 0 | {vbptr}
1> +---
1> +--- (virtual base CBase2)
1> +---
1>CD2::$vbtable@:
1> 0 | 0
1> 1 | 4 (CD2d(CD2+0)CBase2)
1>vbi: class offset o.vbptr o.vbte fVtorDisp
1> CBase2 4 0 4 0
CE:非virtual继承CD2和CDerived2,于是按照类的声明顺序,先带入CDerived2的结构,再带入CD2的结构(而不是按继承顺序)。
{
};
1> +---
1> | +--- (base class CDerived2)
1> 0 | | {vfptr}
1> 4 | | {vbptr}
1> 8 | | derived2
1> | +---
1> | +--- (base class CD2)
1>12 | | {vbptr}
1> | +---
1> +---
1> +--- (virtual base CBase2)
1> +---
1> +--- (virtual base CBase)
1>16 | {vfptr}
1>20 | base
1> +---
1>CE::$vftable@CDerived2@:
1> | &CE_meta
1> | 0
1> 0 | &CDerived2::vfun
1>CE::$vbtable@CD2@:
1> 0 | 0
1> 1 | 4 (CEd(CD2+0)CBase2)
1> 2 | 4 (CEd(CE+12)CBase)
1>CE::$vbtable@CDerived2@:
1> 0 | -4
1> 1 | 12 (CEd(CDerived2+4)CBase)
1>CE::$vftable@CBase@:
1> | -16
1> 0 | &thunk: this-=4; goto CDerived2::fun
1>vbi: class offset o.vbptr o.vbte fVtorDisp
1> CBase2 16 12 4 0
1> CBase 16 12 8 0
CF:virtual继承CBase和CBase2,vbtable此时的项便有两个,此时按照继承的顺序,而不是按照类的声明顺序。
{
};
1> +---
1> 0 | {vbptr}
1> +---
1> +--- (virtual base CBase2)
1> +---
1> +--- (virtual base CBase)
1> 4 | {vfptr}
1> 8 | base
1> +---
1>CF::$vbtable@:
1> 0 | 0
1> 1 | 4 (CFd(CF+0)CBase2)
1> 2 | 4 (CFd(CF+0)CBase)
1>CF::$vftable@:
1> | -4
1> 0 | &CBase::fun
1>vbi: class offset o.vbptr o.vbte fVtorDisp
1> CBase2 4 0 4 0
1> CBase 4 0 8 0