程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 用匯編的眼光看C++(之拷貝、賦值函數)

用匯編的眼光看C++(之拷貝、賦值函數)

編輯:C++入門知識

 

     【 聲明:版權所有,歡迎轉載,請勿用於商業用途。  聯系信箱:feixiaoxing @163.com】

 

 

 

 

    拷貝構造函數和復制函數是類裡面比較重要的兩個函數。兩者有什麼區別呢?其實也很簡單,我們可以舉個例子,加入有這樣一個類的定義:

 

 

copy to clipboardprint?class apple 

public: 

    apple() {  printf("apple()!\n");} 

    apple(apple& a) {  printf("copy apple()!\n");} 

    apple& operator=(apple& a) {  printf("= apple()\n"); return *this;} 

    ~apple() {  printf("~apple()!\n");} 

    void print() const {  return;} 

}; 

class apple

{

public:

       apple() {  printf("apple()!\n");}

       apple(apple& a) {  printf("copy apple()!\n");}

       apple& operator=(apple& a) {  printf("= apple()\n"); return *this;}

       ~apple() {  printf("~apple()!\n");}

       void print() const {  return;}

};

 

 

    那麼我們在如下的函數裡面進行調用的時候,調用的函數分別是哪些呢?

 

 

copy to clipboardprint?void process() 

    apple a, c; 

    apple b =a; 

    c = b; 

void process()

{

       apple a, c;

       apple b =a;

       c = b;

}    其實匯編的結果是這樣的,大家可以一起看一下,自己嘗試讀一下。如果一次不是很明白,可以多讀幾次。

copy to clipboardprint?70:       apple a, c; 

0040127D   lea         ecx,[ebp-10h] 

00401280   call        @ILT+70(apple::apple) (0040104b) 

00401285   mov         dword ptr [ebp-4],0 

0040128C   lea         ecx,[ebp-14h] 

0040128F   call        @ILT+70(apple::apple) (0040104b) 

00401294   mov         byte ptr [ebp-4],1 

71:       apple b =a; 

00401298   lea         eax,[ebp-10h] 

0040129B   push        eax 

0040129C   lea         ecx,[ebp-18h] 

0040129F   call        @ILT+50(apple::apple) (00401037) 

004012A4   mov         byte ptr [ebp-4],2 

72:       c = b; 

004012A8   lea         ecx,[ebp-18h] 

004012AB   push        ecx 

004012AC   lea         ecx,[ebp-14h] 

004012AF   call        @ILT+75(apple::operator=) (00401050) 

73:   } 

004012B4   mov         byte ptr [ebp-4],1 

004012B8   lea         ecx,[ebp-18h] 

004012BB   call        @ILT+0(apple::~apple) (00401005) 

004012C0   mov         byte ptr [ebp-4],0 

004012C4   lea         ecx,[ebp-14h] 

004012C7   call        @ILT+0(apple::~apple) (00401005) 

004012CC   mov         dword ptr [ebp-4],0FFFFFFFFh 

004012D3   lea         ecx,[ebp-10h] 

004012D6   call        @ILT+0(apple::~apple) (00401005) 

004012DB   mov         ecx,dword ptr [ebp-0Ch] 

004012DE   mov         dword ptr fs:[0],ecx 

004012E5   pop         edi 

004012E6   pop         esi 

004012E7   pop         ebx 

004012E8   add         esp,58h 

004012EB   cmp         ebp,esp 

004012ED   call        __chkesp (004087c0) 

004012F2   mov         esp,ebp 

004012F4   pop         ebp 

004012F5   ret 

70:       apple a, c;

0040127D   lea         ecx,[ebp-10h]

00401280   call        @ILT+70(apple::apple) (0040104b)

00401285   mov         dword ptr [ebp-4],0

0040128C   lea         ecx,[ebp-14h]

0040128F   call        @ILT+70(apple::apple) (0040104b)

00401294   mov         byte ptr [ebp-4],1

71:       apple b =a;

00401298   lea         eax,[ebp-10h]

0040129B   push        eax

0040129C   lea         ecx,[ebp-18h]

0040129F   call        @ILT+50(apple::apple) (00401037)

004012A4   mov         byte ptr [ebp-4],2

72:       c = b;

004012A8   lea         ecx,[ebp-18h]

004012AB   push        ecx

004012AC   lea         ecx,[ebp-14h]

004012AF   call        @ILT+75(apple::operator=) (00401050)

73:   }

004012B4   mov         byte ptr [ebp-4],1

004012B8   lea         ecx,[ebp-18h]

004012BB   call        @ILT+0(apple::~apple) (00401005)

004012C0   mov         byte ptr [ebp-4],0

004012C4   lea         ecx,[ebp-14h]

004012C7   call        @ILT+0(apple::~apple) (00401005)

004012CC   mov         dword ptr [ebp-4],0FFFFFFFFh

004012D3   lea         ecx,[ebp-10h]

004012D6   call        @ILT+0(apple::~apple) (00401005)

004012DB   mov         ecx,dword ptr [ebp-0Ch]

004012DE   mov         dword ptr fs:[0],ecx

004012E5   pop         edi

004012E6   pop         esi

004012E7   pop         ebx

004012E8   add         esp,58h

004012EB   cmp         ebp,esp

004012ED   call        __chkesp (004087c0)

004012F2   mov         esp,ebp

004012F4   pop         ebp

004012F5   ret

    代碼有點長,大家可以一句一句來看,比如說就按照70、71、72、73分別查看對應的匯編代碼:

 

    (1)70句: 我們看到函數做了兩次函數調用,恰好就是apple的構造函數調用。這也正好對應著兩個臨時變量a和c,兩個變量的地址分別是【ebp-10】和【ebp-14】,這裡也可以看出整個類的大小就是4個字節,就是一塊存放數據的普通內存。而構造函數之所以能和對應的內存綁定在一起,主要是因為ecx記錄了內存的起始地址,這在C++編譯中是十分關鍵的。我們看到的C++構造函數好像是沒有綁定內存,實際上在VC裡面已經做好了約定,ecx就是this指針,就是類的內存起始地址。有興趣的同學看看G++編譯的時候,采用的this指針是哪個寄存器保存的?(其實是eax)

 

    (2)71句:通過對應看到了eax記錄了引用變量的地址,而ecx是ebp下面緊挨著四個字節。但是函數調用的地址和前面的缺省構造函數不太一樣,所以我們大膽猜測,這裡的構造函數這是拷貝構造函數,我們可以在調試的時候查看一下打印消息。

 

    (3)72句:0x4012AF語句已經清楚地告訴了我們,這裡調用的函數就是operator=函數,這一部分是算術符重載的內容,我們在後面的博客會重點介紹。

 

    (4)73句: 前面我們講過,析構函數在函數調用結束的時候被被自動調用,那麼這裡我們看到卻是出現了三個調用?這三個變量正好是我們之前說的a、b、c三個變量。那麼這三個變量調用的次序是怎樣的呢?我們可以查看一下變量的地址,分別是【ebp-18h】、【ebp-14h】、【ebp-10h】,這正好和變量出現的順序相反。所以我們看到,析構函數和構造函數是嚴格一一對應的,誰先出現,誰後析構。

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