C++虚函数表分析

来源:互联网 发布:外贸帮手网海关数据 编辑:程序博客网 时间:2024/06/06 03:41

         在<<逆向C++>>一文中提到 VC6.0 以上的编译器支持一个d1reportAllClassLayout的开关, 可以输出所有对象的内存布局信息, 我自己常用vs2005来开发,所以这里我就以vs2005为例讲怎么设置d1reportAllClassLayout。

        右键项目属性(Properties)—》配制属性(Configuration Properties)—》C/C++--》命令行(Command Line)的框里输入/d1reportAllClassLayout,即可看类的对象布局,如下图:(当然也可以使用命令行:cl –d1reportSingleClassLayout[classname] test.cpp)


测试代码:

class CBase{public:        virtual void fun(void) {}private:        int m_valuable;};
输出结果:

class CBase size(8): +--- 0 | {vfptr} 4 | m_valuable +---CBase::$vftable@: | &CBase_meta |  0 0 | &CBase::funCBase::fun this adjustor: 0
CDerived:非virtual继承CBase,持有一个virtual重写方法和一个virtual新方法,一个成员变量class CDerived: public CBase{public:void fun(void) { }virtual void vfun(void) { }public:int m_derived;};编译后输出结果:class CDerived size(12): +--- | +--- (base class CBase) 0 | | {vfptr} 4 | | m_valuable | +--- 8 | m_derived +---CDerived::$vftable@: | &CDerived_meta |  0 0 | &CDerived::fun 1 | &CDerived::vfunCDerived::fun this adjustor: 0CDerived::vfun this adjustor: 0其中vftable@CBase的CBase::fun项在这里更新为CDerived::fun,同时增加了一项CDerived::vfun。CDerived2:virtual继承CBase,持有一个virtual重写方法和一个virtual新方法,一个成员变量,因此结构为vftable@自身,vbtable@自身,member@自身,以及CBase结构。总结:class CDerived2: virtual public CBase{public:void fun(void) { }virtual void vfun(void) { }public:int m_derived;};结果输出:class CDerived2 size(20): +--- 0 | {vfptr} 4 | {vbptr} 8 | m_derived +--- +--- (virtual base CBase)12 | {vfptr}16 | m_valuable +---CDerived2::$vftable@CDerived2@: | &CDerived2_meta |  0 0 | &CDerived2::vfunCDerived2::$vbtable@: 0 | -4 1 | 8 (CDerived2d(CDerived2+4)CBase)CDerived2::$vftable@CBase@: | -12 0 | &CDerived2::funCDerived2::fun this adjustor: 12CDerived2::vfun this adjustor: 0vbi:    class  offset o.vbptr  o.vbte fVtorDisp           CBase      12       4       4 0其中vftable@自身只有一项:CDerived2::vfun(),vbtable@自身只有一项:它virtual继承的父类CBase,而vftable@CBase原来的CBase::fun更新为CDerived2::fun。CDerived3:virtual继承CBase,因此结构为vbtable@自身,member@自身,CBase结构class CDerived3: virtual public CBase{public:void fun(void) { }public:int m_derived3;};结果输出:class CDerived3 size(16): +--- 0 | {vbptr} 4 | m_derived3 +--- +--- (virtual base CBase) 8 | {vfptr}12 | m_valuable +---CDerived3::$vbtable@: 0 | 0 1 | 8 (CDerived3d(CDerived3+0)CBase)CDerived3::$vftable@: | -8 0 | &CDerived3::funCDerived3::fun this adjustor: 8vbi:    class  offset o.vbptr  o.vbte fVtorDisp           CBase       8       0       4 0CGDerived:继承CDerived2、CDerived3class CGDerived: public CDerived2, public CDerived3{public:void vfun() { }virtual void vgfun() { }public:int m_gd;};输出:class CGDerived size(32): +--- | +--- (base class CDerived2) 0 | | {vfptr} 4 | | {vbptr} 8 | | m_derived | +--- | +--- (base class CDerived3)12 | | {vbptr}16 | | m_derived3 | +---20 | m_gd +--- +--- (virtual base CBase)24 | {vfptr}28 | m_valuable +---CGDerived::$vftable@CDerived2@: | &CGDerived_meta |  0 0 | &CGDerived::vfun 1 | &CGDerived::vgfunCGDerived::$vbtable@CDerived2@: 0 | -4 1 | 20 (CGDerivedd(CDerived2+4)CBase)CGDerived::$vbtable@CDerived3@: 0 | 0 1 | 12 (CGDerivedd(CDerived3+0)CBase)CGDerived::$vftable@CBase@: | -24 0 | &thunk: this-=12; goto CDerived2::funCGDerived::vfun this adjustor: 0CGDerived::vgfun this adjustor: 0vbi:    class  offset o.vbptr  o.vbte fVtorDisp           CBase      24       4       4 0因此首先是CDerived2的结构和CDerived3的结构,自己的新virtual方法vgfun则添加在最左父类CDerived2的虚函数表中。然后是自己的成员。最后,CDerived2和CDerived3的父类CBase结构也带入其中。它的fun默认指向CGDerived的最左父类CDerived2::fun。CGG:继承CGDerivedclass CGG: public CGDerived{public:int m_kc;};输出:class CGG size(36): +--- | +--- (base class CGDerived) | | +--- (base class CDerived2) 0 | | | {vfptr} 4 | | | {vbptr} 8 | | | m_derived | | +--- | | +--- (base class CDerived3)12 | | | {vbptr}16 | | | m_derived3 | | +---20 | | m_gd | +---24 | m_kc +--- +--- (virtual base CBase)28 | {vfptr}32 | m_valuable +---CGG::$vftable@CDerived2@: | &CGG_meta |  0 0 | &CGDerived::vfun 1 | &CGDerived::vgfunCGG::$vbtable@CDerived2@: 0 | -4 1 | 24 (CGGd(CDerived2+4)CBase)CGG::$vbtable@CDerived3@: 0 | 0 1 | 16 (CGGd(CDerived3+0)CBase)CGG::$vftable@CBase@: | -28 0 | &thunk: this-=16; goto CDerived2::funvbi:    class  offset o.vbptr  o.vbte fVtorDisp           CBase      28       4       4 0增加一个变量,基本只是把CGDerived的结构再套一层,最后加上自己的成员变量。vbtable所指向的父类结构依然在最后。空类class CBase2{};输出:class CBase2 size(1): +--- +---CD2:virtual继承则一定会创建vbtable,用vbptr指针指向,因此size为4class CD2: virtual public CBase2{};输出:class CD2 size(4): +--- 0 | {vbptr} +--- +--- (virtual base CBase2) +---CD2::$vbtable@: 0 | 0 1 | 4 (CD2d(CD2+0)CBase2)vbi:    class  offset o.vbptr  o.vbte fVtorDisp          CBase2       4       0       4 0CE:非virtual继承CD2和CDerived2,于是按照类的声明顺序,先带入CDerived2的结构,再带入CD2的结构(而不是按继承顺序)class CE: public CD2, public CDerived2{};输出:class CE size(24): +--- | +--- (base class CDerived2) 0 | | {vfptr} 4 | | {vbptr} 8 | | m_derived | +--- | +--- (base class CD2)12 | | {vbptr} | +--- +--- +--- (virtual base CBase2) +--- +--- (virtual base CBase)16 | {vfptr}20 | m_valuable +---CE::$vftable@CDerived2@: | &CE_meta |  0 0 | &CDerived2::vfunCE::$vbtable@CD2@: 0 | 0 1 | 4 (CEd(CD2+0)CBase2) 2 | 4 (CEd(CE+12)CBase)CE::$vbtable@CDerived2@: 0 | -4 1 | 12 (CEd(CDerived2+4)CBase)CE::$vftable@CBase@: | -16 0 | &thunk: this-=4; goto CDerived2::funvbi:    class  offset o.vbptr  o.vbte fVtorDisp          CBase2      16      12       4 0           CBase      16      12       8 0CF:virtual继承CBase和CBase2,vbtable此时的项便有两个,此时按照继承的顺序,而不是按照类的声明顺序class CF: virtual public CBase2, virtual public CBase{};输出:class CF size(12): +--- 0 | {vbptr} +--- +--- (virtual base CBase2) +--- +--- (virtual base CBase) 4 | {vfptr} 8 | m_valuable +---CF::$vbtable@: 0 | 0 1 | 4 (CFd(CF+0)CBase2) 2 | 4 (CFd(CF+0)CBase)CF::$vftable@: | -4 0 | &CBase::funvbi:    class  offset o.vbptr  o.vbte fVtorDisp          CBase2       4       0       4 0           CBase       4       0       8 0

总结:

 继承方式:非virtual继承:导入各个父类的结构(按照父类声明的顺序,从上到下),自身member在最后

         重写virtual方法:更新该方法最早定义的类的vftable

        新的virtual方法:在最左父类的vftable增加

 继承方式:有virtual继承:在自身member后增加virtual父类的结构(按照子类继承的顺序从左到右),同时在最前面增加vbtable(如果没有的话),增加一项指向父类结构

         重写virtual方法:更新该方法的最早定义的类的vftable

         新的virtual方法:在自身最前面增加vftable(如果没有的话),在自己的vftable增加


附 所有源码:

#ifndef TEST_CBASE_H#define TEST_CBASE_Hclass CBase{public:CBase();explicit CBase(int valuabel);~CBase();virtual void fun(void) {}private:int m_valuable;};class CDerived: public CBase{public:void fun(void) { }virtual void vfun(void) { }public:int m_derived;};class CDerived2: virtual public CBase{public:void fun(void) { }virtual void vfun(void) { }public:int m_derived;};class CDerived3: virtual public CBase{public:void fun(void) { }public:int m_derived3;};class CGDerived: public CDerived2, public CDerived3{public:void vfun() { }virtual void vgfun() { }public:int m_gd;};class CGG: public CGDerived{public:int m_kc;};class CBase2{};class CD2: virtual public CBase2{};class CE: public CD2, public CDerived2{};class CF: virtual public CBase2, virtual public CBase{};#endif//TEST_CBASE_H


0 0