在對象D的構造函數內只會調用一次祖父類A的構造函數,編譯器在調用類B、C、D的構造函數時,增添一個名爲「構造標記」的參數。例如在調用B:B()構造函數時,「構造標記」=0時,則不調用用父類A的構造函數;「構造標記」=1時,則調用父類A的構造函數。在調用D:D()構造函數時,「構造標記」=0時,則不調用用祖父類A的構造函數;「構造標記」=1時,則調用祖父類A的構造函數。函數
具體過程以下:ui
①「構造標記」置1,而後調用D:D();this
②在D:D()內,調用A:A();spa
③在D:D()內,「構造標記」置0,而後調用B:B();scala
④在D:D()內,「構造標記」置0,而後調用C:C();指針
// 定義傢俱類,等同於類A class CFurniture{ public: CFurniture(){ m_nPrice = 0; } virtual ~CFurniture(){ // 傢俱類的虛析構函數 printf("virtual ~CFurniture()\r\n"); } virtual int GetPrice(){ // 獲取傢俱價格 return m_nPrice; }; protected: int m_nPrice; // 傢俱類的成員變量 }; // 定義沙發類,繼承自類CFurniture,等同於類B class CSofa : virtual public CFurniture{ public: CSofa(){ m_nPrice = 1; m_nColor = 2; } virtual ~CSofa(){ // 沙發類虛析構函數 printf("virtual ~CSofa()\r\n"); } virtual int GetColor(){ // 獲取沙發顏色 return m_nColor; } virtual int SitDown(){ // 沙發能夠坐下休息 return printf("Sit down and rest your legs\r\n"); } protected: int m_nColor; // 沙發類成員變量 }; // 定義牀類,繼承自類CFurniture,等同於類C class CBed : virtual public CFurniture{ public: CBed(){ m_nPrice = 3; m_nLength = 4; m_nWidth = 5; } virtual ~CBed(){ // 牀類的虛析構函數 printf("virtual ~CBed()\r\n"); } virtual int GetArea(){ // 獲取牀面積 return m_nLength * m_nWidth; } virtual int Sleep(){ // 牀能夠用來睡覺 return printf("go to sleep\r\n"); } protected: int m_nLength; // 牀類成員變量 int m_nWidth; }; // 子類沙發牀的定義,派生自類CSofa和類CBed,等同於類D class CSofaBed : public CSofa, public CBed{ public: CSofaBed(){ m_nHeight = 6; } virtual ~CSofaBed(){ // 沙發牀類的虛析構函數 printf("virtual ~CSofaBed()\r\n"); } virtual int SitDown(){ // 沙發能夠坐下休息 return printf("Sit down on the sofa bed\r\n"); } virtual int Sleep(){ // 牀能夠用來睡覺 return printf("go to sleep on the sofa bed\r\n"); } virtual int GetHeight(){ return m_nHeight; } protected: int m_nHeight; // 沙發類的成員變量 }; void main(int argc, char* argv[]){ CSofaBed SofaBed; }
;偏移 地址 值 值解析 ebp-28h 002BF950 00CD4854 pvftable1---->const CSofaBed::`vftable'{for `CSofa'} ebp-24h 002BF954 00CD4870 pvbtable1---->const CSofaBed::`vbtable'{for `CSofa'} ebp-20h 002BF958 00000002 CSofa.m_nColor ebp-1Ch 002BF95C 00CD4844 pvftable2---->const CSofaBed::`vftable'{for `CBed'} ebp-18h 002BF960 00CD4864 pvbtable2---->const CSofaBed::`vbtable'{for `CBed'} ebp-14h 002BF964 00000004 CBed.m_nLength ebp-10h 002BF968 00000005 CBed.m_nWidth ebp-0Ch 002BF96C 00000006 CSofaBed.m_nHeight ebp-08h 002BF970 00CD4834 pvftable3---->const CSofaBed::`vftable'{for `CFurniture'} ebp-04h 002BF974 00000003 CFurniture.m_nPrice ;第一個虛表(pvftable1): ;const CSofaBed::`vftable'{for `CSofa'} ;基類CSofa的虛表 00CD4854 00CD10B4 CSofa::GetColor(void) 00CD4858 00CD1005 CSofaBed::SitDown(void) 00CD485C 00CD1127 CSofaBed::GetHeight(void) 00CD4860 00000000 ;第一個虛基表(vbtable1): ;const CSofaBed::`vbtable'{for `CSofa'} 00CD4870 FFFFFFFC ;vbtable1[1]=-4, address[pvbtable1]+vbtable1[1]=address[pvftable1] 00CD4874 0000001C ;vbtable1[2]=28, address[pvbtable1]+vbtable1[2]=address[pvftable3] 00CD4878 00000000 ;第二個虛表(pvftable2): ;const CSofaBed::`vftable'{for `CBed'} ;基類CBed的虛表 00CD4844 00CD10FA CBed::GetArea(void) 00CD4848 00CD1091 CSofaBed::Sleep(void) 00CD484C 00000000 ;第二個虛基表(vbtable2): ;const CSofaBed::`vbtable'{for `CBed'} 00CD4864 FFFFFFFC ;vbtable2[1]=-4, address[pvbtable2]+vbtable2[1]=address[pvftable2] 00CD4868 00000010 ;vbtable2[2]=16, address[pvbtable2]+vbtable2[2]=address[pvftable3] 00CD486C 00000000 ;第三個虛表(pvftable3): ;const CSofaBed::`vftable'{for `CFurniture'} ;虛基類CFurniture的虛表 00CD4834 00CD1028 CSofaBed::`scalar deleting destructor'(uint) 00CD4838 00CD1145 CFurniture::GetPrice(void) 00CD483C 00000000
mov [ebp-4], ecx ;臨時保存this指針到[ebp-4] mov dword ptr [ebp-48h], 0 ;構造標記置0 cmp dword ptr [ebp+8], 0 ;函數參數[ebp+8]==0,爲0時不須要調用祖父類的構造函數;爲1時,須要調用祖父類的構造函數。 jz short loc_4114BC mov eax, [ebp-4] ;eax=this ;初始化爲[eax+4]=[this+4]=pvbtable1,對pvbtable1初始化爲const CSofaBed::`vbtable'{for `CSofa'} mov dword ptr [eax+4], offset ??_8CSofaBed@@7BCSofa@@@ mov eax, [ebp-4] ;eax=this ;初始化爲[eax+10h]=[this+10h]=pvbtable2,對pvbtable2初始化爲const CSofaBed::`vbtable'{for `CBed'} mov dword ptr [eax+10h], offset ??_8CSofaBed@@7BCBed@@@ mov ecx, [ebp-4] ;ecx=this add ecx, 20h ;ecx+20h=this+20h----->pvftable3 call j_??0CFurniture@@QAE@XZ ;調用祖父類構造函數CFurniture::CFurniture(void) or dword ptr [ebp-48h], 1 ;構造標記置1 loc_4114BC: push 0 ;壓入參數0,做爲構造標記,跳過虛基類CFurniture的構造函數 mov ecx, [ebp-4] ;ecx=this call j_??0CSofa@@QAE@XZ ;調用父類構造函數CSofa::CSofa(void) push 0 ;壓入參數0,做爲構造標記,跳過虛基類CFurniture的構造函數 mov ecx, [ebp-4] ;ecx=this add ecx, 0Ch ;ecx=this+0ch----->pvftable2 call j_??0CBed@@QAE@XZ ;調用父類構造函數CBed::CBed(void) mov eax, [ebp-4] ;ecx=this ;[eax]=[this]----->pvftable1,初始化爲const CSofaBed::`vftable'{for `CSofa'} mov dword ptr [eax], offset ??_7CSofaBed@@6BCSofa@@@ mov eax, [ebp-4] ;ecx=this ;ecx=this+0ch----->pvftable2,初始化爲 const CSofaBed::`vftable'{for `CBed'} mov dword ptr [eax+0Ch], offset ??_7CSofaBed@@6BCBed@@@ mov eax, [ebp-4] ;eax=this mov ecx, [eax+4] ;ecx=[this+4]=pvbtable1 mov edx, [ecx+4] ;edx=[pvbtable1+4]=vbtable1[2] mov eax, [ebp-4] ;eax=this=address[pvftable1] ;[eax+edx+4]=[this+vbtable1[2]]----->pvftable3,初始化爲const CSofaBed::`vftable'{for `CFurniture'} mov dword ptr [eax+edx+4], offset ??_7CSofaBed@@6BCFurniture@@@ mov eax, [ebp-4] ;eax=this mov dword ptr [eax+1Ch], 6 ;[eax+1ch]=[this+1ch]----->CSofaBed.m_nHeight,初始化爲6
略rest
CFurniture * pFurniture = &SofaBed; mov ecx, [ebp-24h] ;參照棧表可知,ecx=[ebp-24h]=[this+4]=pvbtable1,指向第一個虛基表 mov edx, [ecx+4] ;edx=[pvbtable1+4]=vbtable2[2] lea eax, [ebp+edx-24h]
;pvbtable1+vbtable2[2]=address[pvftable3],即eax=address[pvftable3]=this+20h。 mov [ebp-78h], eax mov ecx, [ebp-78h] mov [ebp-2Ch], ecx ;指針變量pFurniture在[ebp-2Ch]處,即pFurniture=this+20h ;printf("price is %d", pFurniture->GetPrice()); mov eax, [ebp-2Ch] ;把pFurniture賦值給eax,即eax=this+20h mov edx, [eax] ;edx=[this+20h]=pvftable3 mov ecx, [ebp-2Ch] ;ecx傳參,ecx=this+20h----->pvftable3 mov eax, [edx+4]
;eax=[pvftable3+4]=vftable3[2]----->CFurniture::GetPrice(void) call eax ;調用CFurniture::GetPrice(void) push eax ;CFurniture::GetPrice(void)返回的結果入棧 push offset Format ;"price is %d" call ds:__imp__printf add esp, 8 ;CSofa * pSofa = &SofaBed; lea eax, [ebp-28h] ;參照棧表可知,eax=address[ebp-28h]=this mov [ebp-30h], eax ;指針變量pSofa在棧[ebp-30h]處,完成pSofa的賦值,即pSofa=this ;pSofa->SitDown(); mov eax, [ebp-30h] ;eax=pSofa=this mov edx, [eax] ;edx=[this]=pvftable1 mov ecx, [ebp-30h] ;ecx傳參,ecx=pSofa=this mov eax, [edx+4]
;eax=[pvftable1+4]=vftable1[2]----->CSofaBed::SitDown(void) call eax ;調用CSofaBed::SitDown(void) CBed * pBed = &SofaBed; lea ecx, [ebp-28h] ;參照棧表可知,ecx=address[ebp-28h]=this add ecx, 0Ch ;ecx=this+0ch----->pvftable2 mov [ebp-78h], ecx ; jmp short loc_41142E ;---| ;| loc_41142E:;<----------------| mov edx, [ebp-78h] mov [ebp-34h], edx
;指針變量pBed在棧[ebp-34h]處,完成pBed的賦值,即pBed=this+0ch----->pvftable2 pBed->Sleep(); mov eax, [ebp-34h] ;eax=this+0ch mov edx, [eax] ;edx=[this+0ch]=pvftable2 mov ecx, [ebp-34h] ;ecx傳參,ecx=this+0ch----->pvftable2 mov eax, [edx+4]
;eax=[pvftable2+4]=vftable2[2]----->CSofaBed::Sleep(void) call eax ;調用CSofaBed::Sleep(void)