【 聲明:版權所有,歡迎轉載,請勿用於商業用途。 聯系信箱: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行很正常,不要害怕,孰能生巧