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

用匯編的眼光看c++(之模板函數)

編輯:C++入門知識

如果說模板類定義的是一種數據類型,那麼模板函數定義的就是一種函數。既然是函數,那麼就有輸入數據和輸出數據。和模板類的概念差不多,模板函數的初衷也是為了在函數操作上抽取共同的特性,屏蔽的是類型的不同和差異。我們可以通過下面一個簡單的代碼說明問題:
  view plain int int_compare(int a, int b)
  { return a > b ? a : b;}
  double double_compare(int a, int b)
  { return a > b ? a : b;}上面的一段代碼是取較大值的一段代碼。兩個函數之間最大的差別就是輸入數據類型和輸出數據類型之間的差別,那我們有沒有一種辦法可以屏蔽這種數據類型之間的差別呢?有。那就是函數模板:view plain template <typename type> type compare(type a, type b)
  { return a > b ? a : b;}可以看到,模板函數和普通函數沒有什麼區別,只是在函數的上面把類型抽象成了type,那麼模板函數應該怎麼使用呢?
  view plain 246:      int i_value = compare(2, 3);00401458   push        3 0040145A   push        2 0040145C   call        @ILT+10(compare) (0040100f)
  00401461   add         esp,8 00401464   mov         dword ptr [ebp-4],eax 247:      double d_value = compare(2.3, 3.1);00401467   push        4008CCCCh 0040146C   push        0CCCCCCCDh 00401471   push        40026666h 00401476   push        66666666h 0040147B   call        @ILT+5(compare) (0040100a)
  00401480   add         esp,10h 00401483   fstp        qword ptr [ebp-0Ch] 248:  }匯編代碼表明,兩個compare調用的函數地址並不是一致的。其中整數的compare地址是0x40100f,而double的地址是0x0040100a.這說明編譯器在編譯的時候幫我們同時生成了兩個compare函數。所以說,模板類的本質就是在編譯器增加判斷處理工作的同時,減少手工的重復勞動。同時和模板類不一樣,模板函數不需要顯示定義函數的參數類型,這是因為可以從入參或者是返回參數判斷出函數的類型。
  如果參數類型是 class類型呢? 我們可以試一試。首先定義基本class:
  view plain class data { int value;public:explicit data(int m): value(m) {} ~data() {} int get_value() { return value;} int operator > (data& d) {return this->get_value() > d.get_value();} };接著,我們調用compare函數:view plain 256:      data m(4), n(2);0040148D   push        4 0040148F   lea         ecx,[ebp-10h] 00401492   call        @ILT+40(data::data) (0040102d)
  00401497   mov         dword ptr [ebp-4],0 0040149E   push        2 004014A0   lea         ecx,[ebp-14h] 004014A3   call        @ILT+40(data::data) (0040102d)
  004014A8   mov         byte ptr [ebp-4],1 257:      data p = compare(m,n);004014AC   mov         eax,dword ptr [ebp-14h] 004014AF   push        eax 004014B0   mov         ecx,dword ptr [ebp-10h] 004014B3   push        ecx 004014B4   lea         edx,[ebp-18h] 004014B7   push        edx 004014B8   call        @ILT+15(compare) (00401014)
  004014BD   add         esp,0Ch 258:  } 256行: data構造了兩個基本變量m和n 257行: 我們調用模板函數compare, 函數地址為0x401014,注意dx為p的地址,也就是堆棧臨時變量的地址
  為了看到算術符>重載,我們跟進compare函數:
  view plain 241:      return a > b ? a : b;0040212B   lea         eax,[ebp+10h] 0040212E   push        eax 0040212F   lea         ecx,[ebp+0Ch] 00402132   call        @ILT+55(data::operator>) (0040103c)
  00402137   test        eax,eax 00402139   je          compare+53h (00402143)
  0040213B   lea         ecx,[ebp+0Ch] 0040213E   mov         dword ptr [ebp-18h],ecx 00402141   jmp         compare+59h (00402149)
  00402143   lea         edx,[ebp+10h] 00402146   mov         dword ptr [ebp-18h],edx 00402149   mov         eax,dword ptr [ebp-18h] 0040214C   mov         dword ptr [ebp-10h],eax 0040214F   mov         ecx,dword ptr [ebp-10h] 00402152   mov         edx,dword ptr [ecx] 00402154   mov         eax,dword ptr [ebp+8] 00402157   mov         dword ptr [eax],edx 00402159   mov         ecx,dword ptr [ebp-14h] 0040215C   or          ecx,1 0040215F   mov         dword ptr [ebp-14h],ecx 00402162   mov         byte ptr [ebp-4],1 00402166   lea         ecx,[ebp+0Ch] 00402169   call        @ILT+25(data::~data) (0040101e)
  0040216E   mov         byte ptr [ebp-4],0 00402172   lea         ecx,[ebp+10h] 00402175   call        @ILT+25(data::~data) (0040101e)
  0040217A   mov         eax,dword ptr [ebp+8]我們發現compare模板語句下面構建了很多匯編語句,有一些冗長,我們可以大略介紹一下:(1)  開頭調用call 0x0040103C函數就是調用重載運算符函數,[ebp-18h]表示即將被復制的是a數據還是b數據
  (2) 比較返回結果後,開始復制數據,具體見0x402157,其中臨時變量[ebp-14h]和臨時變量[ebp-4]的操作可以忽略
  (3) 函數返回前,對臨時變量a和b進行析構處理,見代碼0x402169和代碼0x402175.
  注意:
  (1)編寫模板函數前先保證自己的函數是編寫正確的
  (2)模板函數的優先級低於非模板函數
  (3)模板函數的類型可以是自定義類型,也可以是c、c++語言的基本類型
  (4)模板函數的使用經常和類的算術運算符混合使用,注意技巧
  (5)模板函數中涉及指針部分的內容,務必注意

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