程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++類機制的實現細節

C++類機制的實現細節

編輯:C++入門知識

 為了搞清楚VC中類的實現專門寫了一個最簡單的類,用來觀察它的實現過程,代碼如下:
  // test.cpp : Defines the entry point for the console application.
  //

  #include "stdafx.h"
  #include "CTest.h"
    
  int main(int argc, char* argv[])
  {
  CTest aTest;
  aTest.a(1,2);
  return 0;
  }
  
  // CTest.h: interface for the CTest class.
  //
  //////////////////////////////////////////////////////////////////////
  
  #if !defined(AFX_CTEST_H__2CCCDCFC_6C3A_48BC_9CD0_E7A8E63431D9__INCLUDED_)
  #define AFX_CTEST_H__2CCCDCFC_6C3A_48BC_9CD0_E7A8E63431D9__INCLUDED_
  
  #if _MSC_VER > 1000
  #pragma once
  #endif // _MSC_VER > 1000
  
  class CTest 
  {
  public:
  CTest();
  virtual ~CTest();
  
  public:
  void b();
  void a(int one,int two);
  };
  
  #endif // !defined(AFX_CTEST_H__2CCCDCFC_6C3A_48BC_9CD0_E7A8E63431D9__INCLUDED_)
  
  
  // CTest.cpp: implementation of the CTest class.
  //
  //////////////////////////////////////////////////////////////////////
  
  #include "stdafx.h"
  #include "CTest.h"
  
  //////////////////////////////////////////////////////////////////////
  // Construction/Destruction
  //////////////////////////////////////////////////////////////////////
  
  CTest::CTest()
  {
  
  }

  CTest::~CTest()
  {
  
  }
  
  void CTest::b()
  {
  printf("b is be called by a");
  }
  
  void CTest::a(int one,int two)
  {
  printf("call b");
  b();
  }
  
  下面是相應的反匯編代碼:
  --- D:myown est est.cpp ------------
    1:  // test.cpp : Defines the entry point for the console application.
2:  //
  3:
  4:  #include "stdafx.h"
  5:  #include "CTest.h"
  6:
  7:  int main(int argc, char* argv[])
  8:  {
  00401050  push    ebp
  00401051  mov     ebp,esp
  00401053  push    0FFh
  00401055  push    offset __ehhandler$_main (00410c89)
  0040105A  mov     eax,fs:[00000000]
  00401060  push    eax
  00401061  mov     dword ptr fs:[0],esp
  00401068  sub     esp,48h
  0040106B  push    ebx
  0040106C  push    esi
  0040106D  push    edi
  0040106E  lea     edi,[ebp-54h]
  00401071  mov     ecx,12h
  00401076  mov     eax,0CCCCCCCCh
  0040107B  rep stos  dword ptr [edi]
  
  9:    CTest aTest;
  0040107D  lea     ecx,[ebp-10h] file://這是用來保存aTest的this指針,因為是局部變量所以是保存在[ebp-10h]中
  00401080  call    @ILT+30(CTest::CTest) (00401023) file://調用aTest的構造函數,由編譯器自動產生的CALL
  00401085  mov     dword ptr [ebp-4],0
  
  10:    aTest.a(1,2);
  0040108C  push    2
  0040108E  push    1
  00401090  lea     ecx,[ebp-10h] file://把aTest的this指針用ecx進行傳遞
  00401093  call    @ILT+5(CTest::a) (0040100a) 
  11:    return 0;


 00401098  mov     dword ptr [ebp-14h],0
  0040109F  mov     dword ptr [ebp-4],0FFFFFFFFh
  004010A6  lea     ecx,[ebp-10h] file://同樣是this指針
  004010A9  call    @ILT+25(CTest::~CTest) (0040101e) file://aTest的生存周期到了,自動調用析構函數,同樣是由編譯器分析之後自加上去
  004010AE  mov     eax,dword ptr [ebp-14h]
  12:  }
  004010B1  mov     ecx,dword ptr [ebp-0Ch]
  004010B4  mov     dword ptr fs:[0],ecx
  004010BB  pop     edi
  004010BC  pop     esi
  004010BD  pop     ebx
  004010BE  add     esp,54h
  004010C1  cmp     ebp,esp
  004010C3  call    __chkesp (00401670)
  004010C8  mov     esp,ebp
  004010CA  pop     ebp
  004010CB  ret
  
  下面再來分析一下VC中對函數的調用:
  可以看到上面有對三個函數的調用分別為:
  00401080  call    @ILT+30(CTest::CTest) (00401023)
  00401093  call    @ILT+5(CTest::a) (0040100a)
  004010A9  call    @ILT+25(CTest::~CTest) (0040101e)
  
  可以看到他們都跳到了以@ILT為基的一個地址去了,那麼跳過去之後可以看到:
  @ILT+0(??_GCTest@@UAEPAXI@Z):
  00401005  jmp     CTest::`scalar deleting destructor (00401130)
  @ILT+5(?a@CTest@@QAEXHH@Z):
  0040100A  jmp     CTest::a (00401230)
  @ILT+10(_main):
  0040100F  jmp     main (00401050)
  @ILT+15(?b@CTest@@QAEXXZ):
  00401014  jmp     CTest::b (004011e0)
  @ILT+20(??_GCTest@@UAEPAXI@Z):
  00401019  jmp     CTest::`scalar deleting destructor (00401130)
  @ILT+25(??1CTest@@UAE@XZ):
  0040101E  jmp     CTest::~CTest (004011a0)
  @ILT+30(??0CTest@@QAE@XZ):
  00401023  jmp     CTest::CTest (004010f0)
  
  這個@ILT其實就是一個靜態的表,它記錄了一些函數的入口然後跳過去,每個跳轉jmp占一個字節,然後就是一個四字節的內存地址,所以加起為五個字節,這樣就實現了類的機制。
  
  下面再來分析一下,類的成員函數調用另一成員函數的情況:
  
  27:  void CTest::a(int one,int two)

  28:  {
  00401230  push    ebp
  00401231  mov     ebp,esp
  00401233  sub     esp,44h
  00401236  push    ebx
  00401237  push    esi
  00401238  push    edi
  00401239  push    ecx
  0040123A  lea     edi,[ebp-44h]
  0040123D  mov     ecx,11h
  00401242  mov     eax,0CCCCCCCCh
  00401247  rep stos  dword ptr [edi]
  00401249  pop     ecx
  0040124A  mov     dword ptr [ebp-4],ecx
  29:    printf("call b");
  0040124D  push    offset string "call b" (00422038)
  00401252  call    printf (00401830)
  00401257  add     esp,4
  30:    b();
  0040125A  mov     ecx,dword ptr [ebp-4] file://不要想這裡的[ebp-4]肯定是this指針,
  0040125D  call    @ILT+15(CTest::b) (00401014) // 又是@ILT靜態表格
  31:  }
  00401262  pop     edi
  00401263  pop     esi
  00401264  pop     ebx
  00401265  add     esp,44h
  00401268  cmp     ebp,esp
  0040126A  call    __chkesp (00401670)
  0040126F  mov     esp,ebp
  00401271  pop     ebp
  00401272  ret     8   file://由於是STDCALLR所以棧是由程序自己來平衡的

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved