Liny_@NotePad

沉迷ACG中

【20090821】C++培训日记-虚函数表

YOYO posted @ 2009年8月21日 19:51 in 【C/C++】 with tags 虚函数表 virtual 对象布局 , 4313 阅读

检测方法(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()。

class CBase
{
public:
        virtual void fun(void) {  }
 
public:
        int base;
};
1>class CBase size(8):
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。

class CDerived: public CBase
{
public:
        void fun(void) { }
        virtual void vfun(void) { }

public:
        int derived;
};
1>class CDerived size(12):
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。

class CDerived2: virtual public CBase
{
public:
        void fun(void) { }
        virtual void vfun(void) { }

public:
        int derived2;
};
1>class CDerived2 size(20):
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结构。

class CDerived3: virtual public CBase
{
public:
        void fun(void) { }

public:
        int derived3;
};
1>class CDerived3 size(16):
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。

class CGDerived: public CDerived2, public CDerived3
{
public:
        void vfun() { }
        virtual void vgfun() { }

public:
        int gd;
};
1>class CGDerived size(32):
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所指向的父类结构依然在最后。

class CGG: public CGDerived
{
public:
        int kc;
};
1>class CGG size(36):
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

class CBase2
{

};
1>class CBase2 size(1):
1> +---
1> +---

CD2:virtual继承则一定会创建vbtable,用vbptr指针指向,因此size为4。

class CD2: virtual public CBase2
{

};
1>class CD2 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的结构(而不是按继承顺序)。

class CE: public CD2, public CDerived2
{

};
1>class CE size(24):
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此时的项便有两个,此时按照继承的顺序,而不是按照类的声明顺序。

class CF: virtual public CBase2, virtual public CBase
{

};
1>class CF size(12):
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

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter