前言
今天博主將要介紹的內(nèi)容是–模板,他在C++中具有非常重要的位置.至于什么是模板呢?我們請看下面的章節(jié).
引入
我們對交換函數(shù)Swap已經(jīng)非常熟悉了,但是我們經(jīng)常會遇到這樣的一些事,比如,很多不同的數(shù)據(jù)類型進(jìn)行交換,那么我們就需要寫不同的重載Swap,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
#include <iostream> using namespace std; void Swap( int & a, int & b){ int t = a; a = b; b = t; } void Swap( double & a, double & b){ double t = a; a = b; b = t; } int main() { int a = 10,b = 20; double c = 1.2,d = 3.4; Swap(a,b); Swap(c,d); return 0; } |
可以看到,如果有必要,我們需要交換幾種類型的數(shù)據(jù),就必須寫上幾種重載Swap,這就導(dǎo)致非常的繁瑣,因為我們對其交換邏輯太熟悉了,只是換了變量類型,那有什么辦法可以解決呢?沒錯,這就是我們今天要講的模板.
模板
概念:在生活中,博主舉一個例子,假設(shè)你是一個手辦廠家,現(xiàn)在你需要售出各種材料和顏色做的悟空手辦,首先你需要的就是悟空的模型,然后按照這個模型使用不同的材料.這個模型就是我們在程序中的模板.
模板種類:
- 函數(shù)模板
- 類模板
函數(shù)模板
函數(shù)模板的格式:
1
2
3
4
|
template < class T1, class T2,...> return_val function_name (para1,para1,...) { } |
打省略號的都是形參列表,表示參數(shù)量自由,我們現(xiàn)在知道了怎樣使用函數(shù)模板,那試試寫一個Swap模板:
1
2
3
4
5
6
7
|
template < class T> void Swap (T& a,T& b) { T t = a; a = b; b = a; } |
按照模板規(guī)范,我們寫出來了Swap的模板,現(xiàn)在測試一下結(jié)果是否正確呢?
發(fā)現(xiàn)測試結(jié)果完全正確.
然后這里博主有個疑問,就是我們調(diào)用Swap時,編譯器是執(zhí)行的上面模板呢?還是執(zhí)行的通過模板推演出來的函數(shù)呢?
答:通過模板推演出來的函數(shù),因為C++提出模板是為了節(jié)省程序員的時間,我們所省略的工作,只是編譯器替我們完成了.
也就是說,比如我們這樣調(diào)用:
1
2
3
4
5
6
|
int main() { int a = 10,b = 20; Swap(a,b); return 0; } |
那么編譯器在底部會推演出一個如下函數(shù),并執(zhí)行:
1
2
3
4
5
|
void Swap( int & a, int & b){ int t = a; a = b; b = t; } |
模板的匹配原則
什么叫做模板的匹配原則呢?
就是說當(dāng)既有定義出來的明確函數(shù),同時又有模板,那么調(diào)用函數(shù)時候,執(zhí)行的是哪一個?以下面為例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
void Swap( int & a, int & b){ int t = a; a = b; b = t; } template < class T> void Swap (T& a,T& b) { T t = a; a = b; b = a; } int main() { int a = 10,b = 20; Swap(a,b); return 0; } |
匹配順序為:
- 如果有定義出來的函數(shù),且類型完全匹配調(diào)用時實參類型,則執(zhí)行定義出來的函數(shù).
- 如果定義出來的函數(shù),不符合,則執(zhí)行模板推演.
也就是說,上面的例子中,Swap調(diào)用的是我們定義出來的Swap,而不是模板.
模板的顯示調(diào)用
上面講解的模板使用,其實被稱做隱式調(diào)用,現(xiàn)在,博主介紹一下顯示調(diào)用.
顯示調(diào)用格式:
1
|
function<Type1,Type2,..>(para1,para1,...); |
也就是說,我們明確知道需要使用的什么類型,并且就想告訴編譯器,我傳給你的是什么類型,然后讓編譯器推演出該類型的函數(shù).比如下面使用:
1
2
3
4
|
int a = 10,b = 20; char c = 'a' ,d = 'b' ; Swap< int >(a,b); //告訴編譯器我傳的是int類型 Swap< char >(c,d); //告訴編譯器我傳的是char類型 |
大家可能會問了,這有什么用呢?既然編譯器會根據(jù)我們的調(diào)用情況進(jìn)行推演,還進(jìn)行顯示調(diào)用不是多此一舉嗎?大家請看下面的代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
template < class T> void Swap (T& a,T& b) { T t = a; a = b; b = a; } int main() { int a = 10; double b = 23.22; Swap(a,b); //這樣調(diào)用編譯器就會報錯 return 0; } |
像上面的調(diào)用方式,是不允許的,因為模板中只有一個T,但是我們傳了兩個類型,編譯器根據(jù)模板將不知道T應(yīng)該是啥類型,而解決上面的問題只有兩種
- 一是強(qiáng)制性轉(zhuǎn)換類型,比如Swap(a,(int)b);
- 二是顯示使用模板,比如Swap<int>(a,b);
其次,博主講解模板的顯示調(diào)用還有一個目的就是為了引出下面的類模板.
類模板
類模板和函數(shù)模板相似,定義框架如下:
1
2
3
4
|
template < class T1, class T2,...> class class_name { }; |
我們對數(shù)據(jù)結(jié)構(gòu)—棧,應(yīng)該算比較了解,而對于經(jīng)常刷力扣的伙伴來說,可能會發(fā)現(xiàn)棧不只是用來存儲int類型,比如還有ListNode*等,那我們大概寫一下其stack模板吧.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
template < class T> class Stack { public : Stack():data( new T*[10]),top(0),capacity(10) {} ~Stack() { delete [] data; top = capacity = 0; } void Push(T& a) {} private : T* data; int top; int capacity; }; |
然后我們定義Stack對象,但是對象應(yīng)該存儲的類型是什么呢?如果我們繼續(xù)用最開始的隱式模板方法,發(fā)現(xiàn)完全實現(xiàn)不了,這也就是博主上面為何要講解模板的顯示調(diào)用,因為類模板只能通過顯示調(diào)用實現(xiàn),例子使用如下:
1
2
3
|
Stack < char > st1; //定義一個存儲char類型的棧 Stack < int > st2; //定義一個存儲int類型的棧 Stack < double > st3; //定義一個存儲double類型的棧 |
Stack并不是類,其只是一個模板,Stack <int>等才是類
注意1
類模板只是一個模板,他并不屬于類.
注意2
當(dāng)我們的模板類中的成員函數(shù),在模板中聲明,而在模板外定義時,需要加上模板參數(shù)列表,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
template < class T> class Stack { public : void Push(T& a); bool empty(); private : T* data; int top; int capacity; }; template < class T> void Stack<T>:: Push(T& a) //需要加上template <class T> ,且在Stack后面加上<T> {} template < class T> void Stack<T>:: empty() //需要加上template <class T> ,且在Stack后面加上<T> {} |
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注服務(wù)器之家的更多內(nèi)容!
原文鏈接:https://blog.csdn.net/m0_51723227/article/details/120997774