C++函數(shù)模板
在《C++函數(shù)重載》一節(jié)中,為了交換不同類型的變量的值,我們通過函數(shù)重載定義了四個(gè)名字相同、參數(shù)列表不同的函數(shù),下面一起來學(xué)習(xí)一下吧!
//交換 int 變量的值
void Swap(int *a, int *b){
int temp = *a;
*a = *b;
*b = temp;
}
//交換 float 變量的值
void Swap(float *a, float *b){
float temp = *a;
*a = *b;
*b = temp;
}
//交換 char 變量的值
void Swap(char *a, char *b){
char temp = *a;
*a = *b;
*b = temp;
}
//交換 bool 變量的值
void Swap(bool *a, bool *b){
char temp = *a;
*a = *b;
*b = temp;
}
這些函數(shù)雖然在調(diào)用時(shí)方便了一些,但從本質(zhì)上說還是定義了三個(gè)功能相同、函數(shù)體相同的函數(shù),只是數(shù)據(jù)的類型不同而已,這看起來有點(diǎn)浪費(fèi)代碼,能不能把它們壓縮成一個(gè)函數(shù)呢?
我們知道,數(shù)據(jù)的值可以通過函數(shù)參數(shù)傳遞,在函數(shù)定義時(shí)數(shù)據(jù)的值是未知的,只有等到函數(shù)調(diào)用時(shí)接收了實(shí)參才能確定其值。這就是值的參數(shù)化。
在C++中,數(shù)據(jù)的類型也可以通過參數(shù)來傳遞,在函數(shù)定義時(shí)可以不指明具體的數(shù)據(jù)類型,當(dāng)發(fā)生函數(shù)調(diào)用時(shí),編譯器可以根據(jù)傳入的實(shí)參自動(dòng)推斷數(shù)據(jù)類型。這就是類型的參數(shù)化。
值(Value)和類型(Type)是數(shù)據(jù)的兩個(gè)主要特征,它們?cè)贑++中都可以被參數(shù)化。
所謂函數(shù)模板,實(shí)際上是建立一個(gè)通用函數(shù),它所用到的數(shù)據(jù)的類型(包括返回值類型、形參類型、局部變量類型)可以不具體指定,而是用一個(gè)虛擬的類型來代替(實(shí)際上是用一個(gè)標(biāo)識(shí)符來占位),等發(fā)生函數(shù)調(diào)用時(shí)再根據(jù)傳入的實(shí)參來逆推出真正的類型。這個(gè)通用函數(shù)就稱為函數(shù)模板(Function Template)。
在函數(shù)模板中,數(shù)據(jù)的值和類型都被參數(shù)化了,發(fā)生函數(shù)調(diào)用時(shí)編譯器會(huì)根據(jù)傳入的實(shí)參來推演形參的值和類型。換個(gè)角度說,函數(shù)模板除了支持值的參數(shù)化,還支持類型的參數(shù)化。
一但定義了函數(shù)模板,就可以將類型參數(shù)用于函數(shù)定義和函數(shù)聲明了。說得直白一點(diǎn),原來使用 int、float、char 等內(nèi)置類型的地方,都可以用類型參數(shù)來代替。
下面我們就來實(shí)踐一下,將上面的四個(gè)Swap() 函數(shù)壓縮為一個(gè)函數(shù)模板:
#include
using namespace std;
templatevoid Swap(T *a, T *b){
T temp = *a;
*a = *b;
*b = temp;
}
int main(){
//交換 int 變量的值
int n1 = 100, n2 = 200;
Swap(&n1, &n2);
cout<<n1<<", "<<n2<<endl;
//交換 float 變量的值
float f1 = 12.5, f2 = 56.93;
Swap(&f1, &f2);
cout<<f1<<", "<<f2<<endl;
//交換 char 變量的值
char c1 = 'A', c2 = 'B';
Swap(&c1, &c2);
cout<<c1<<", "<<c2<<endl;
//交換 bool 變量的值
bool b1 = false, b2 = true;
Swap(&b1, &b2);
cout<<b1<<", "<<b2<<endl;
return 0;
}
運(yùn)行結(jié)果:
200, 100
56.93, 12.5
B, A
1, 0
請(qǐng)讀者重點(diǎn)關(guān)注第 4 行代碼。template是定義函數(shù)模板的關(guān)鍵字,它后面緊跟尖括號(hào)<>,尖括號(hào)包圍的是類型參數(shù)(也可以說是虛擬的類型,或者說是類型占位符)。typename是另外一個(gè)關(guān)鍵字,用來聲明具體的類型參數(shù),這里的類型參數(shù)就是T。從整體上看,template被稱為模板頭。
模板頭中包含的類型參數(shù)可以用在函數(shù)定義的各個(gè)位置,包括返回值、形參列表和函數(shù)體;本例我們?cè)谛螀⒘斜砗秃瘮?shù)體中使用了類型參數(shù)T。
類型參數(shù)的命名規(guī)則跟其他標(biāo)識(shí)符的命名規(guī)則一樣,不過使用 T、T1、T2、Type 等已經(jīng)成為了一種慣例。
定義了函數(shù)模板后,就可以像調(diào)用普通函數(shù)一樣來調(diào)用它們了。
在講解C++函數(shù)重載時(shí)我們還沒有學(xué)到引用(Reference),為了達(dá)到交換兩個(gè)變量的值的目的只能使用指針,而現(xiàn)在我們已經(jīng)對(duì)引用進(jìn)行了深入講解,不妨趁此機(jī)會(huì)來實(shí)踐一把,使用引用重新實(shí)現(xiàn) Swap() 這個(gè)函數(shù)模板:
#include
using namespace std;
templatevoid Swap(T &a, T &b){
T temp = a;
a = b;
b = temp;
}
int main(){
//交換 int 變量的值
int n1 = 100, n2 = 200;
Swap(n1, n2);
cout<<n1<<", "<<n2<<endl;
//交換 float 變量的值
float f1 = 12.5, f2 = 56.93;
Swap(f1, f2);
cout<<f1<<", "<<f2<<endl;
//交換 char 變量的值
char c1 = 'A', c2 = 'B';
Swap(c1, c2);
cout<<c1<<", "<<c2<<endl;
//交換 bool 變量的值
bool b1 = false, b2 = true;
Swap(b1, b2);
cout<<b1<<", "<<b2<<endl;
return 0;
}
引用不但使得函數(shù)定義簡潔明了,也使得調(diào)用函數(shù)方便了很多。整體來看,引用讓編碼更加漂亮。
下面我們來總結(jié)一下定義模板函數(shù)的語法:
template返回值類型 函數(shù)名(形參列表){
//在函數(shù)體中可以使用類型參數(shù)
}
類型參數(shù)可以有多個(gè),它們之間以逗號(hào),分隔。類型參數(shù)列表以< >包圍,形式參數(shù)列表以( )包圍。
typename關(guān)鍵字也可以使用class關(guān)鍵字替代,它們沒有任何區(qū)別。C++ 早期對(duì)模板的支持并不嚴(yán)謹(jǐn),沒有引入新的關(guān)鍵字,而是用 class 來指明類型參數(shù),但是 class 關(guān)鍵字本來已經(jīng)用在類的定義中了,這樣做顯得不太友好,所以后來 C++ 又引入了一個(gè)新的關(guān)鍵字 typename,專門用來定義類型參數(shù)。不過至今仍然有很多代碼在使用 class 關(guān)鍵字,包括 C++ 標(biāo)準(zhǔn)庫、一些開源程序等。
本教程會(huì)交替使用 typename 和 class,旨在讓讀者在別的地方遇到它們時(shí)不會(huì)感覺陌生。更改上面的 Swap() 函數(shù),使用 class 來指明類型參數(shù):
templatevoid Swap(T &a, T &b){
T temp = a;
a = b;
b = temp;
}
除了將 typename 替換為 class,其他都是一樣的。
為了加深對(duì)函數(shù)模板的理解,我們?cè)賮砜匆粋(gè)求三個(gè)數(shù)的最大值的例子:
#include
using namespace std;
//聲明函數(shù)模板
templateT max(T a, T b, T c);
int main( ){
//求三個(gè)整數(shù)的最大值
int i1, i2, i3, i_max;
cin >> i1 >> i2 >> i3;
i_max = max(i1,i2,i3);
cout << "i_max=" << i_max << endl;
//求三個(gè)浮點(diǎn)數(shù)的最大值
double d1, d2, d3, d_max;
cin >> d1 >> d2 >> d3;
d_max = max(d1,d2,d3);
cout << "d_max=" << d_max << endl;
//求三個(gè)長整型數(shù)的最大值
long g1, g2, g3, g_max;
cin >> g1 >> g2 >> g3;
g_max = max(g1,g2,g3);
cout << "g_max=" << g_max << endl;
return 0;
}
//定義函數(shù)模板
template//模板頭,這里不能有分號(hào)
T max(T a, T b, T c){ //函數(shù)頭
T max_num = a;
if(b > max_num) max_num = b;
if(c > max_num) max_num = c;
return max_num;
}
運(yùn)行結(jié)果:
12 34 100↙
i_max=100
73.234 90.2 878.23↙
d_max=878.23
344 900 1000↙
g_max=1000
函數(shù)模板也可以提前聲明,不過聲明時(shí)需要帶上模板頭,并且模板頭和函數(shù)定義(聲明)是一個(gè)不可分割的整體,它們可以換行,但中間不能有分號(hào)。
【C++函數(shù)】相關(guān)文章:
C++函數(shù)考點(diǎn)歸納09-30
c++函數(shù)指針使用示例07-26
C++如何調(diào)用matlab函數(shù)06-29
C++函數(shù)指針學(xué)習(xí)教程10-01