静态多态之泛型编程(模板)
起初,我們寫不同類型的加法函數是這樣寫的吧:
//Template.h
#pragma onceint Add(const int left,const int right) {return left+right; }char Add(const char left,const char right) {return left+right; }float Add(const float left,const float right) {return left+right; }</span> //Template.cppint main() {cout<<Add(1,2)<<endl;cout<<Add('1','2')<<endl;cout<<Add(1.1f,2.2f)<<endl;return 0; }
運行結果:
是不是特別熟悉呢。對,這就是我們的函數重載。之前為了適應不同類型的參數,我們一直使用的函數重載的方式。但是這種方式有一定的局限性和缺點,比如:
(1)只要有新類型出現,就得新添加函數。
(2)重復的代碼過多,代碼復用率不高。
(3)如果只是函數返回值不同,就不能使用函數重載。
(4)一個方法有問題,所有的方法都有問題,不好維護。
那么,我們還知道什么方法可以解決這些問題呢?
肯定有人會說,使用宏定義的方法。
#define Add(a,b) ((a)+(b))運行結果:
顯然,上述兩種方式打印出來的結果竟然不相同。這是為什么呢?
首先,用宏定義的方式沒有類型檢測,所以致使第二次打印char類型的值時打印成了int型,這樣也使得代碼安全性不高。
其次,宏不是函數,不能調試,如果出錯的話,也會很麻煩。
這里,就給大家引入一個新的概念吧~【模板】
模板是泛型編程的基礎,那么,泛型編程指什么呢,就是編寫與類型無關的邏輯代碼。
模板分為函數模板和類模板,今天給大家講一下函數模板。
一、函數模板
模板的格式:
template<typename T1,typename T2 ...> 【說明:typename是模板參數關鍵字,T1,T2是類型名】那么,對于上述的加法問題,我們就可以寫成這樣的:
//Template.h
template<typename T> T Add(const T& left,const T& right) {return left+right; }
//Template.cpp
int main() {cout<<Add(1,2)<<endl;cout<<Add('1','2')<<endl;cout<<Add(1.1f,2.2f)<<endl;return 0; }</span>
運行結果:
這樣的結果也是和函數重載方式的結果是一樣的。我們可以想到,模板函數的類型是T,而傳入的參數是固定的類型,它是怎么檢測到函數的類型的呢。這里就有模板函數的推演過程。
查看反匯編,當調用第一個Add(1,2)時,
當調用Add('1','2')時:
當調用Add(1.1,2.2)時:
其實背后的推演為這樣的(編譯器會自動的生成相應的函數):
二、模板參數
函數模板有兩種類型參數:模板參數和調用參數。
模板形參分為類型形參和非類型形參。
(1)模板形參的名字只能在模板形參之后到模板聲明或定義之間使用。
(2)模板形參的名字在同一模板形參列表中只能使用一次。
(3)所有模板形參前面必須加class或typename關鍵字。
(4)不能將模板形參作為函數實參。
還有:
(5)函數形參為離它最近的模板形參。
(6)默認的模板參數(在這里是不能使用的,只有在類模板中可使用)
三、非模板類型參數
例:對于數組長度來說,可以這樣定義模板參數:
通過反匯編可以看到內部的實現:
還有另外一種調用方式是:
注:這里的數組arr的類型是int[10],所以T代表的是int[10]哦。
總結一下,模板形參需要注意的點:
(1)模板形參表需使用<>;
(2)模板形參中參數需用逗號隔開;
(3)模板形參表不能為空;
如:
(4)模板形參可以是類型參數(跟在class/typename后),也可以是非類型參數。
(5)模板形參可作為類型說明符用在模板的任何地方,與內置類型或自定義類型使用方法相同,可用于指定函數形參類型、返回值、局部變量、強制類型轉換。
(6)模板形參表中,class和typename有相同的含義,但typename更加直觀,一般多用typename。(注:舊版本可能不支持typename,只支持class)
四、模板函數的特化
為什么會引入模板函數的特化版本呢?
有時候,我們并不能寫出對所有可能被實例化的類型都最合適的模板,此時,我們就會用特化的形式,來實現模板函數。
例:
//Template.h
template<typename T> T Add(const T& left,const T& right) {return left+right; }template<> //特化版本 int Add<int>(const int& left,const int& right) {return left+right; }//Template.cpp
int main() {cout<<Add(1,2)<<endl;return 0; }
此時,Add(1,2)函數會調用哪個模板函數呢?
這里要知道,如果是特化版本中有實參類型,就直接調用特化版本。好處是:不用進行模板參數的類型推演過程。
下面再看一個例子:
//Template.h
#pragma once #include<string.h>template<typename T> T Max(const T left,const T right) {return (left > right) ? left:right; }template<> char* Max<char*>(char* const str1,char* const str2) {if(strcmp(str1,str2) == 0 || strcmp(str1,str2) == 1){return str1;}else{return str2;} } //Template.cpp
#include"Template.h" #include<iostream> using namespace std; int main() {char* str1 = "zello";char* str2 = "world";cout<<Max<char*>(str1,str2)<<endl;return 0; }運行結果:
注:在這里要特別注意的是const的位置,它修飾的是字符串,而不是char*哦。
模板就先說到這里啦~~
下一篇博客,會寫到模板類的實現哦。歡迎大家來訪嘍,并給出好的建議和意見哦。
總結
以上是生活随笔為你收集整理的静态多态之泛型编程(模板)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python之字典
- 下一篇: 【送给Git初学者】