構造函數中調用虛函數

#include <iostream>

using namespace std;

class Base
{
 public:

  Base(void);
  virtual ~Base();
  virtual void Foo(void);

 private:
  int m_b;
};

Base::Base(void) : m_b(0x123) //爲了便於在彙編代碼中定位 賦值爲 0x123
{
 cout << "Base construction" << endl;
 cout << "call Foo in Base construction" << endl;
 Foo();
}

Base::~Base()
{
 cout << "Base destruction" << endl;
}

void Base::Foo(void)
{
 cout << "Base Foo" << endl;
}

class Derive : public Base
{
 public:
  Derive(void);
  ~Derive();

  virtual void Foo(void);

 private:
  int m_d;
};

Derive::Derive(void) : Base(), m_d(0x456)
{
 cout << "Derive construction" << endl;
}

Derive::~Derive()
{
 cout << "Derive destruction" << endl;
}

void Derive::Foo(void)
{
 cout << "Derive Foo" << endl;
}


int main(int argc, char* argv[])
{
 cout << "create Base instance" << endl;
 Base base;

 cout << endl << "create Derive instance" << endl;
 Derive derive;

 cout << endl << "create Derive instance by new" << endl;
 Base* bptr = new Derive;
 bptr->Foo();

 delete bptr;

 return 0;
}

運行結果:

create Base instance
Base construction
call Foo in Base construction
Base Foo

create Derive instance
Base construction
call Foo in Base construction
Base Foo
Derive construction

create Derive instance by new
Base construction
call Foo in Base construction
Base Foo
Derive construction
Derive Foo
Derive destruction
Base destruction

 

構造函數的彙編代碼                              

:00401168 push ebp                     ;Base的構造函數起始位置 
:00401169 mov ebp, esp
:0040116B add esp, FFFFFFDC
:0040116E mov eax, 00402184
:00401173 call 00401C0C
:00401178 mov [ebp-14], 0008
:0040117E mov edx, 004023C0            ;將Base類的虛函數表 vtable地址004023C0 放入edx
:00401183 mov ecx, dword ptr [ebp+08]  ;ecx = this
:00401186 mov dword ptr [ecx], edx     ;將Base類的虛函數表 vtable地址004023C0 放入Base的this指針指向的地址
:00401188 mov eax, dword ptr [ebp+08]
:0040118B mov [eax+04], 00000123       ;初始化成員變量m_b爲0x123 
:00401192 push 004020A4
:00401197 mov edx, dword ptr [00405184]
:0040119D push edx
:0040119E call 004011F8
:004011A3 add esp, 00000008
:004011A6 push eax
:004011A7 call 004015A8
:004011AC pop ecx
:004011AD push 004020B6
:004011B2 mov ecx, dword ptr [00405184]
:004011B8 push ecx
:004011B9 call 004011F8
:004011BE add esp, 00000008
:004011C1 push eax
:004011C2 call 004015A8
:004011C7 pop ecx
:004011C8 mov eax, dword ptr [ebp+08]      ;eax = this
:004011CB push eax
:004011CC mov edx, dword ptr [eax]         ;edx = 虛函數表 vtable的地址
:004011CE call [edx+04]                    ;調用Foo
:004011D1 pop ecx
:004011D2 mov ecx, dword ptr [ebp-24]
:004011D5 mov dword ptr fs:[00000000], ecx
:004011DC mov eax, dword ptr [ebp+08]
:004011DF mov esp, ebp
:004011E1 pop ebp
:004011E2 ret

:004017D8 push ebp                        ;Derive的構造函數起始位置   
:004017D9 mov ebp, esp                      
:004017DB add esp, FFFFFFDC                 
:004017DE mov eax, 004022B0                 
:004017E3 call 00401C0C                     
:004017E8 mov [ebp-14], 0008                
:004017EE mov edx, dword ptr [ebp+08]     ;edx = this  
:004017F1 push edx                          
:004017F2 call 00401168                   ;調用Base的構造函數  
:004017F7 pop ecx                           
:004017F8 inc [ebp-08]                      
:004017FB mov ecx, 004023AC               ;將Derive類的虛函數表 vtable的地址004023AC 放入ecx  
:00401800 mov eax, dword ptr [ebp+08]     ;eax = this    
:00401803 mov dword ptr [eax], ecx        ;將Derive類的虛函數表 vtable的地址004023AC 放入Derive的this指針所指向的地址  
:00401805 mov edx, dword ptr [ebp+08]     ;edx = this    
:00401808 mov [edx+08], 00000456          ;初始化成員變量m_d爲0x456, [this]是虛函數表地址 
:0040180F push 004020EE                   ;[this+04]是Base的m_b [this+08]是Derive的m_d  
:00401814 mov ecx, dword ptr [00405184]     
:0040181A push ecx                          
:0040181B call 004011F8                     
:00401820 add esp, 00000008                 
:00401823 push eax                          
:00401824 call 004015A8                     
:00401829 pop ecx                           
:0040182A mov eax, dword ptr [ebp-24]       
:0040182D mov dword ptr fs:[00000000], eax  
:00401833 mov eax, dword ptr [ebp+08]       
:00401836 mov esp, ebp                      
:00401838 pop ebp                           
:00401839 ret                               

 

包含虛函數的類的起始地址處保存的是虛函數表的地址,這個地址值是由類的構造函數填寫進去的。
在生成派生類Derive的實例時,由Derive的構造函數來調用Base的構造函數先完成基類Base的構建。Base的構造函數中調用虛函數Foo,此時從虛函數表中獲取的只能是Base類的虛函數表的地址,因此虛函數Foo綁定的是Base類的Foo,只能執行Base的Foo。

在生成派生類Derive的實例時,Derive的this指針指向的地址其實首先被Base的構造函數填充一次,然後又被Derive的構造函數填充一次。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章