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

用匯編的眼光看C++(之模板類)

編輯:C++入門知識

 

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

 

 

 

    如果類是一種確定的數據類型,那麼模板就是一種對類的抽象。假設有這麼一種類,它需要進行數據的計算,而且類型還很多,那麼我們可能就要針對不同類型的數據定義不同的類。我們可以用下面一段代碼說明問題:

class int_process 

    int a; 

    int b; 

public: 

    int_process(int m, int n):a(m), b(n) {} 

    ~int_process() {} 

    int add() {return a + b;} 

    int sub() {return a - b;} 

    int mul() {return a * b;} 

    int div() {return a / b;} 

}; 

 

class short_process 

    short a; 

    short b; 

public: 

    short_process(short m, short n):a(m), b(n) {} 

    ~short_process() {} 

    short add() {return a + b;} 

    short sub() {return a - b;} 

    short mul() {return a * b;} 

    short div() {return a / b;} 

}; 

class int_process

{

       int a;

       int b;

public:

       int_process(int m, int n):a(m), b(n) {}

       ~int_process() {}

       int add() {return a + b;}

       int sub() {return a - b;}

       int mul() {return a * b;}

       int div() {return a / b;}

};

 

class short_process

{

       short a;

       short b;

public:

       short_process(short m, short n):a(m), b(n) {}

       ~short_process() {}

       short add() {return a + b;}

       short sub() {return a - b;}

       short mul() {return a * b;}

       short div() {return a / b;}

};

    上面的代碼內容其實比較簡單,大家可以看明白。第一個類是int_process,主要是整數的加、減、乘、除的計算。第二類是short_process,主要處理的短整數的加、減、乘、除計算。兩個類處理的內容其實非常相似。那麼有沒有一種簡單的辦法可以同時處理這兩個類?有!這就是模板。我們可以把具體的數據類型抽象出來,形成一種新的類模式。這就是模板類。下面的代碼就是模板類:

template <typename type> 

class data_process 

    type a; 

    type b; 

public: 

    data_process(type m, type n):a(m), b(n) {} 

    ~data_process() {} 

    type add() {return a + b;} 

    type sub() {return a - b;} 

    type mul() {return a * b;} 

    type div() {return a / b;} 

}; 

template <typename type>

class data_process

{

       type a;

       type b;

public:

       data_process(type m, type n):a(m), b(n) {}

       ~data_process() {}

       type add() {return a + b;}

       type sub() {return a - b;}

       type mul() {return a * b;}

       type div() {return a / b;}

};

    我們看到類把具體的數據類型都抽象成了type。至此,不管是輸入值、輸出數值,我們都換成了type。至於類的名稱,我們也從原來特定的數據類型計算,轉變成了通用的data_process,當然這種名稱的定義不是太重要的。那麼模板類定義之後,我們應該怎麼應用呢?大家繼續看代碼:

void process() 

    data_process<int> d(1,2); 

    data_process<char> m('1', '2'); 

    data_process<double> p(1.2, 2.3); 

void process()

{

       data_process<int> d(1,2);

       data_process<char> m('1', '2');

       data_process<double> p(1.2, 2.3);

}    大家從上面的代碼也看的出,模板類的定義並不復雜,只是在模板類的名稱之後添加一下具體的數據類型就可以了。如果是int類型的,那麼處理int的數據;同理,如果處理的是char或者是double類型數據,我們就可以按照char或者是double類型的數據進行計算,十分方便。當談,處理的數據遠遠不止C++語言本身定義的char、double、float、int、short、long這幾種數據類型,如果type本身就是一種class類型,同時這樣class類型也支持+、-、*、/運算,那麼本身也是可以用作模板的。我們這裡介紹int、char、double只是為了簡單地說明問題。看到類的聲明後,我們不禁有一個疑問,既然模板類只有一個,那麼這些模板類的構造函數、析構函數、成員函數的處理都相同嗎?我們不妨看看看一看他們的匯編代碼:

60:       data_process<int> d(1,2); 

0040126D   push        2 

0040126F   push        1 

00401271   lea         ecx,[ebp-14h] 

00401274   call        @ILT+45(data_process<int>::data_process<int>) (00401032) 

00401279   mov         dword ptr [ebp-4],0 

61:       data_process<char> m('1', '2'); 

00401280   push        32h 

00401282   push        31h 

00401284   lea         ecx,[ebp-18h] 

00401287   call        @ILT+55(data_process<char>::data_process<char>) (0040103c) 

0040128C   mov         byte ptr [ebp-4],1 

62:       data_process<double> p(1.2, 2.3); 

00401290   push        40026666h 

00401295   push        66666666h 

0040129A   push        3FF33333h 

0040129F   push        33333333h 

004012A4   lea         ecx,[ebp-28h] 

004012A7   call        @ILT+60(data_process<double>::data_process<double>) (00401041) 

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

63:       int i_d = d.add(); 

004012B0   lea         ecx,[ebp-14h] 

004012B3   call        @ILT+70(data_process<int>::add) (0040104b) 

004012B8   mov         dword ptr [ebp-2Ch],eax 

64:       char c_m = m.add(); 

004012BB   lea         ecx,[ebp-18h] 

004012BE   call        @ILT+80(data_process<char>::add) (00401055) 

004012C3   mov         byte ptr [ebp-30h],al 

65:       double d_p = p.add(); 

004012C6   lea         ecx,[ebp-28h] 

004012C9   call        @ILT+75(data_process<double>::add) (00401050) 

004012CE   fstp        qword ptr [ebp-38h] 

66: 

67:   } 

60:       data_process<int> d(1,2);

0040126D   push        2

0040126F   push        1

00401271   lea         ecx,[ebp-14h]

00401274   call        @ILT+45(data_process<int>::data_process<int>) (00401032)

00401279   mov         dword ptr [ebp-4],0

61:       data_process<char> m('1', '2');

00401280   push        32h

00401282   push        31h

00401284   lea         ecx,[ebp-18h]

00401287   call        @ILT+55(data_process<char>::data_process<char>) (0040103c)

0040128C   mov         byte ptr [ebp-4],1

62:       data_process<double> p(1.2, 2.3);

00401290   push        40026666h

00401295   push        66666666h

0040129A   push        3FF33333h

0040129F   push        33333333h

004012A4   lea         ecx,[ebp-28h]

004012A7   call        @ILT+60(data_process<double>::data_process<double>) (00401041)

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

63:       int i_d = d.add();

004012B0   lea         ecx,[ebp-14h]

004012B3   call        @ILT+70(data_process<int>::add) (0040104b)

004012B8   mov         dword ptr [ebp-2Ch],eax

64:       char c_m = m.add();

004012BB   lea         ecx,[ebp-18h]

004012BE   call        @ILT+80(data_process<char>::add) (00401055)

004012C3   mov         byte ptr [ebp-30h],al

65:       double d_p = p.add();

004012C6   lea         ecx,[ebp-28h]

004012C9   call        @ILT+75(data_process<double>::add) (00401050)

004012CE   fstp        qword ptr [ebp-38h]

66:

67:   }

    上面的代碼有點長,我們大家來一起看一下:

    60句: 定義int型的class類型,可以看到data_process<int>構造函數地址是0x401032

    61句: 定義char型的class類型,看到data_process<char>構造函數地址是0x40103c

    62句:定義double型的class類型,看到data_process<double>構造函數地址是0x401041

    63句:調用data_process<int>的add成員函數,地址為0x40104b

    64句:調用data_process<char>的add成員函數,地址為0x401055

    65句:調用data_process<double>的add成員函數,地址為0x401050

   

    上面的代碼表明,其實編譯器為我們函數中出現的每一個具體類實例化了一遍。針對每一個類型,模板的構造函數、析構函數、成員函數都要獨立生成,這從上面的函數地址就可以看出來,沒有什麼神奇的。所以,我們明白了模板的本質就是對不同數據類型的相似性操作進行共同屬性提取,合成模板。在應用的時候,編譯器根據我們使用中的數據類型獨立生成每一個類,構建每一個基本運算變量和運算函數,僅此而已。

 

 

模板注意事項:

    (1)class上出現的問題在模板類上都會出現

    (2)先把class寫好,然後再轉變成模板類

    (3)如果不是數據類型的差異,而是共有數據數量上的差異,請選用繼承代替模板

    (4)模板中的type可以是自定義類型

    (5)模板代碼只能出現在頭文件中,出現在*.cpp文件中沒有意義,單獨的*.cpp模板代碼因為沒有涉及具體類型,因此不會編譯成任何二進制代碼

    (6)不同版本的vc對模板支持有差異,編譯錯誤不一定是你自己的原因,但是絕大部分應該是你的原因

    (7)模板生成的告警很冗長,一個warning或者是error 30~50行很正常,不要害怕,孰能生巧

 

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