C++中建構函式能調用虛函數嗎?(答案是文法可以,輸出錯誤),但Java裡居然可以

來源:互聯網
上載者:User

標籤:文法   知識   replace   ble   source   gic   call   題目   地址   

      環境:XPSP3 VS2005

        今天黑總給應聘者出了一個在C++的建構函式中調用虛函數的問題,具體的題目要比標題複雜,大體情況可以看如下的代碼:

[cpp] view plain copy 
  1. class Base  
  2. {  
  3. public:  
  4.     Base()  
  5.     {  
  6.         Fuction();  
  7.     }  
  8.   
  9.     virtual void Fuction()  
  10.     {  
  11.         cout << "Base::Fuction" << endl;  
  12.     }  
  13. };  
  14.   
  15. class A : public Base  
  16. {  
  17. public:  
  18.     A()  
  19.     {  
  20.         Fuction();  
  21.     }  
  22.   
  23.     virtual void Fuction()  
  24.     {  
  25.         cout << "A::Fuction" << endl;  
  26.     }  
  27. };  
  28.   
  29. // 這樣定義一個A的對象,會輸出什嗎?  
  30. A a;  

        首先回答標題的問題,調用當然是沒有問題的,但是獲得的是你想要的結果嗎?或者說你想要什麼樣的結果?

        有人說會輸出:

[html] view plain copy 
  1. A::Fuction  
  2. A::Fuction  

        如果是這樣,首先我們回顧下C++物件模型裡面的構造順序,在構造一個子類對象的時候,首先會構造它的基類,如果有多層繼承關係,實際上會從最頂層的基類逐層往下構造(虛繼承、多重繼承這裡不討論),如果是按照上面的情形進行輸出的話,那就是說在構造Base的時候,也就是在Base的建構函式中調用Fuction的時候,調用了子類A的Fuction,而實際上A還沒有開始構造,這樣函數的行為就是完全不可預測的,因此顯然不是這樣,實際的輸出結果是:

[html] view plain copy 
  1. Base::Fuction  
  2. A::Fuction  

        據說在Java中是上一種輸出(感覺有點匪夷所思)。

        我們來單步看一下到底發生了什嗎?在A的建構函式裡面首先會去調用Base的建構函式,Base的建構函式如下:

class Base
{
public:
 Base()
00411600  push        ebp  
00411601  mov         ebp,esp 
00411603  sub         esp,0CCh 
00411609  push        ebx  
0041160A  push        esi  
0041160B  push        edi  
0041160C  push        ecx  
0041160D  lea         edi,[ebp-0CCh] 
00411613  mov         ecx,33h 
00411618  mov         eax,0CCCCCCCCh 
0041161D  rep stos    dword ptr es:[edi] 
0041161F  pop         ecx  
00411620  mov         dword ptr [ebp-8],ecx 
00411623  mov         eax,dword ptr [this] 
00411626  mov         dword ptr [eax],offset Base::`vftable‘ (41770Ch)
 {
  Fuction();
0041162C  mov         ecx,dword ptr [this] 
0041162F  call        Base::Fuction (4111A9h)

 }
00411634  mov         eax,dword ptr [this] 
00411637  pop         edi  
00411638  pop         esi  
00411639  pop         ebx  
0041163A  add         esp,0CCh 
00411640  cmp         ebp,esp 
00411642  call        @ILT+460(__RTC_CheckEsp) (4111D1h) 
00411647  mov         esp,ebp 
00411649  pop         ebp  
0041164A  ret

        從單步跟蹤來看,注意黑色加粗的那部分彙編代碼,ecx中存放的是對象的地址(0x0012ff60,我的機器上的情況看,有圖有真相),首先是設定vtable的地址到對象的前四個位元組(不同的編譯器可能不同),然後就直接調用了Base::Fuction函數,並沒有走虛機制,而我們此時看虛表中的狀態,虛表已經填充的是0x4111a9,注意虛表的地址0x0041770c,而此時對象地址0x0012FF60前四個位元組存放的正是0x0041770c。

        繼續跟蹤,流程又回到A的建構函式中,再次注意加粗部分的代碼,從基類Base的建構函式返回後,在A的建構函式中,重設了虛表指標,現在的虛表指標是(0x417700h),同樣調用Fuction的時候直接調用了A::Fuction函數,並沒有使用虛機制,而且此時虛表0x417700h指向的位置存放的0x41110e正是A::Fuction的地址。

class A : public Base
{
public:
 A()
00411590  push        ebp  
00411591  mov         ebp,esp 
00411593  sub         esp,0CCh 
00411599  push        ebx  
0041159A  push        esi  
0041159B  push        edi  
0041159C  push        ecx  
0041159D  lea         edi,[ebp-0CCh] 
004115A3  mov         ecx,33h 
004115A8  mov         eax,0CCCCCCCCh 
004115AD  rep stos    dword ptr es:[edi] 
004115AF  pop         ecx  
004115B0  mov         dword ptr [ebp-8],ecx 
004115B3  mov         ecx,dword ptr [this] 
004115B6  call        Base::Base (411140h) 
004115BB  mov         eax,dword ptr [this] 
004115BE  mov         dword ptr [eax],offset A::`vftable‘ (417700h)
 {
  Fuction();
004115C4  mov         ecx,dword ptr [this] 
004115C7  call        A::Fuction (41110Eh)
 }
004115CC  mov         eax,dword ptr [this] 
004115CF  pop         edi  
004115D0  pop         esi  
004115D1  pop         ebx  
004115D2  add         esp,0CCh 
004115D8  cmp         ebp,esp 
004115DA  call        @ILT+460(__RTC_CheckEsp) (4111D1h) 
004115DF  mov         esp,ebp 
004115E1  pop         ebp  
004115E2  ret


        其實事情就是這麼簡單。

 

http://blog.csdn.net/magictong/article/details/6734241

C++中建構函式能調用虛函數嗎?(答案是文法可以,輸出錯誤),但Java裡居然可以

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.