一、泛型編程思想
- 首先我們來看一下下面這三個(gè)函數(shù),如果學(xué)習(xí)過了?C++函數(shù)重載?和?C++引用?的話,就可以知道下面這三個(gè)函數(shù)是可以共存的,而且傳值會(huì)很方便
-
void Swap(int& left, int& right) { int temp = left; left = right; right = temp; } void Swap(double& left, double& right) { double temp = left; left = right; right = temp; } void Swap(char& left, char& right) { char temp = left; left = right; right = temp; }
但是真的很方便嗎?這里只有三種類型的數(shù)據(jù)需要交換,若是我們需要增加交換的數(shù)據(jù)呢?再CV然后寫一個(gè)函數(shù)嗎?
?這肯定是不現(xiàn)實(shí)的,所以很明顯函數(shù)重載雖然可以實(shí)現(xiàn),但是有一下幾個(gè)不好的地方:
- 重載的函數(shù)僅僅是類型不同,代碼復(fù)用率比較低,只要有新類型出現(xiàn)時(shí),就需要用戶自己增加對(duì)應(yīng)的函數(shù)
- 代碼的可維護(hù)性比較低,一個(gè)出錯(cuò)可能所有的重載均出錯(cuò)
?那是否能做到這么一點(diǎn),告訴編譯器一個(gè)模子,讓編譯器根據(jù)不同的類型利用該模子來生成代碼
這樣,我們先通過一個(gè)案例來做引入
- 才高八斗的魏武帝之子【曹植】曾經(jīng)寫過一首《洛神賦》,被后人譽(yù)為“千古第一絕世神仙詩”,因此在那個(gè)時(shí)候被很多文人所抄錄、傳唱,其共1089個(gè)字,想要一字不落地抄錄下來還是需要時(shí)間,那古代還有一些更長(zhǎng)的詩賦,例如:《離騷》,足足有2500多字,若也是一個(gè)一個(gè)地抄錄下來的話,那會(huì)變得極為麻煩
- 于是呢古人又發(fā)明了一種東西叫做【活字印刷術(shù)】,有了此技術(shù)之后,人們不再需要每次去手抄一些詩賦書籍,只需要作一份模版字體,然后在其上刷上水,刷上墨,然后拿紙這么一印,就可以得到一份工整的印刷體了
???? 所以,總結(jié)上面的這么一個(gè)技術(shù),C++的祖師爺呢就想到了【模版】這個(gè)東西,告訴編譯器一個(gè)模子,然后其余的工作交給它來完成,根據(jù)不同的需求生成不同的代碼
這就是??泛型編程:編寫與類型無關(guān)的通用代碼,是代碼復(fù)用的一種手段。模板是泛型編程的基礎(chǔ)
二、函數(shù)模版
知曉了模版的基本概念后,首先我們要來看的就是【函數(shù)模版】
1、函數(shù)模板概念
函數(shù)模板代表了一個(gè)函數(shù)家族,該函數(shù)模板與類型無關(guān),在使用時(shí)被參數(shù)化,根據(jù)實(shí)參類型產(chǎn)生函數(shù)的特定類型版本
通過函數(shù)模板,可以編寫一種通用的函數(shù)定義,使其能夠適用于多種數(shù)據(jù)類型,從而提高代碼的復(fù)用性和靈活性。
2、函數(shù)模板格式
- 然后正式來聲明一個(gè)函數(shù)模版,這里我們要學(xué)一個(gè)新的關(guān)鍵字叫template,接下去加一個(gè)<>尖括號(hào),內(nèi)部就是模版的參數(shù)了,可以使用typename或者class來進(jìn)行類型的聲明(不可以用struct),若是只有一個(gè)類型的話我們一般會(huì)叫做【T】,不過這個(gè)沒有強(qiáng)制要求
template<typename T1, typename T2,......,typename Tn>
- 接下去就可以使用上面所聲明的模版參數(shù)了,即上面的這個(gè)【T】,它和我們普通的函數(shù)參數(shù)可不一樣,后者是定義的是對(duì)象,而前者定義的是類型
返回值類型 函數(shù)名(參數(shù)列表){}
馬上,我們就來為上面的
swap()
函數(shù)寫一個(gè)通用的函數(shù)模版把template<typename T> void Swap(T& left, T& right) { T temp = left; left = right; right = temp; }
- 然后來用一用這個(gè)函數(shù)模版,分別傳入不同數(shù)據(jù)類型的參數(shù),通過結(jié)果的觀察可以發(fā)現(xiàn)這個(gè)函數(shù)模版可以根據(jù)不同的類型去做一個(gè)自動(dòng)推導(dǎo),繼而去起到一個(gè)交換的功能
- 我們可以通過調(diào)試來進(jìn)一步觀察,發(fā)現(xiàn)無論是對(duì)于【整型】還是【浮點(diǎn)型】,都會(huì)去走這個(gè)
Swap()
函數(shù),函數(shù)模版都可以進(jìn)行自動(dòng)的識(shí)別
?那我現(xiàn)在想問一個(gè)問題,請(qǐng)問它們調(diào)用的真的是同一個(gè)函數(shù)嗎?
- ?相信很多同學(xué)都說是的,上面不是演示過了嗎?但是看完下面這一小節(jié)你就不會(huì)這么說了??
?3、函數(shù)模板的原理
接下去我們來說說這個(gè)函數(shù)模版的原理,帶你理清編譯器內(nèi)部究竟做了什么事情
- 對(duì)于函數(shù)模板而言其實(shí)是一個(gè)【藍(lán)圖】,它本身并不是函數(shù),是編譯器用使用方式產(chǎn)生特定具體類型函數(shù)的模具。所以其實(shí)模板就是將本來應(yīng)該我們做的重復(fù)的事情交給了編譯器,讓我們來看看編譯器做了什么
- 可以發(fā)現(xiàn),在進(jìn)行匯編代碼查看的時(shí)候,被調(diào)用的函數(shù)模版生成了兩個(gè)不同的函數(shù),它們有著不同的函數(shù)地址,因此可以回答上一小節(jié)所提出的問題了,兩次所調(diào)用的函數(shù)是不一樣的,是根據(jù)函數(shù)模版所生成的
還是不太懂的老鐵可以看看下面這張圖,就能明白了
- 在編譯器編譯階段,對(duì)于模板函數(shù)的使用,編譯器需要根據(jù)傳入的實(shí)參類型來推演生成對(duì)應(yīng)類型的函數(shù)以供調(diào)用。比如:當(dāng)用int類型使用函數(shù)模板時(shí),編譯器通過對(duì)實(shí)參類型的推演,將T確定為int類型,然后產(chǎn)生一份專門處理int類型的代碼,對(duì)于浮點(diǎn)類型、字符型也是如此
??? 那我現(xiàn)在還想問,如果我使用的是兩個(gè)日期類Date
的對(duì)象呢,能不能對(duì)它們進(jìn)行交換
- ?答案是可以的,int、double、char這些都是內(nèi)置類型,Date呢是自定義類型,很明顯它們都是類型,我們所定義的模版參數(shù)也是類型,那為何不可去做一個(gè)接受呢?從運(yùn)行結(jié)果可以來看,確實(shí)是可以發(fā)現(xiàn)它們也發(fā)生了一個(gè)交換
?? 那如果是指針呢?也會(huì)去調(diào)用嗎?
- ?如何你學(xué)的扎實(shí)得話,立馬就能反應(yīng)過來了,對(duì)于指針而言也是內(nèi)置類型,那既然是類型的話為何不能調(diào)用呢?
既然談到了這個(gè)【Swap】交換函數(shù),我們就順便來說說庫里的這個(gè)【swap】
- 仔細(xì)觀察下圖可以發(fā)現(xiàn)我將Swap前面大寫S改成了小寫s,它就是std標(biāo)準(zhǔn)庫的里面的一個(gè)函數(shù),也包含在STL的基本算法中
- 進(jìn)到文檔里面進(jìn)行查看我們可以發(fā)現(xiàn)這個(gè)函數(shù)確實(shí)已經(jīng)實(shí)現(xiàn)了【函數(shù)模版】,因此可以接收任何類型的數(shù)據(jù),所以在學(xué)習(xí)了函數(shù)模版后我們就不需要自己再去寫
swap()
函數(shù)了,直接用庫里的即可
4、函數(shù)模板的實(shí)例化
上面我們所定義的都是單個(gè)模版參數(shù),那多個(gè)模版參數(shù)是否可以定義呢?
- 這個(gè)當(dāng)然是可以的,我們立馬來試試看吧
template<typename T1, typename T2> T1 Func(const T1& x, const T2& y) { cout << x << " " << y << endl; }
- 通過運(yùn)行可以發(fā)現(xiàn),是完全可以做到的,去定義多個(gè)模版參數(shù),這個(gè)特性本文就不做距離了,等我們學(xué)習(xí)了一些STL之后再【模版進(jìn)階】一文中詳解
然后我們來講講【函數(shù)模板的實(shí)例化】
?? 用不同類型的參數(shù)使用函數(shù)模板時(shí),稱為函數(shù)模板的實(shí)例化。模板參數(shù)實(shí)例化分為:隱式實(shí)例化和顯式實(shí)例化
- 隱式實(shí)例化:讓編譯器根據(jù)實(shí)參推演模板參數(shù)的實(shí)際類型
- 知道模版可以定義多個(gè)參數(shù)之后,其返回值也可以是模版參數(shù)
template<class T> T Add(const T& left, const T& right) { return left + right; }
- 下面這種就是【隱式實(shí)例化】,讓編譯器根據(jù)實(shí)參自動(dòng)去推導(dǎo)模板參數(shù)的實(shí)際類型,然后返回返回不同類型的數(shù)據(jù)
int main() { int a1 = 10, a2 = 20; double d1 = 10.0, d2 = 20.0; // 根據(jù)實(shí)參傳遞的類型,推演T的類型 cout << Add(a1, a2) << endl; cout << Add(d1, d2) << endl; }
-
但是呢像下面這種就不可以了,因?yàn)閍1是【int】類型,d1是【double】類型,在編譯期間,當(dāng)編譯器看到該實(shí)例化時(shí),需要推演其實(shí)參類型 通過實(shí)參a1將T推演為int類型,通過實(shí)參d1將T推演為double類型,但模板參數(shù)列表中只有一個(gè)T, 編譯器無法確定此處到底該將T確定為int 或者 double類型而報(bào)錯(cuò)。此時(shí)在函數(shù)調(diào)用完后進(jìn)行返回時(shí),編譯器也識(shí)別不出是哪個(gè)類型了,它們兩個(gè)就像在打架一樣,很難一絕高下
cout << Add(a1, d2) << endl
好比你做錯(cuò)事了,你爸爸讓你罰站,不讓你吃飯,此時(shí)呢你媽媽回來了,讓你趕緊過來吃飯,那此時(shí)你該聽誰的呢?
- 那此時(shí)呢就需要爸爸媽媽回房間商量一下了,到底是以誰說的話為主呢
那當(dāng)他們商量好了之后,就會(huì)有下面這兩種情況
- 這一種改法便是聽爸爸的,后者d1強(qiáng)轉(zhuǎn)為
int
類型然后再傳遞進(jìn)去,此時(shí)就不會(huì)出現(xiàn)類型沖突的問題了cout << Add(a1, (int)d2) << endl;
- 這種改法便是聽媽媽的,前者a1強(qiáng)轉(zhuǎn)為
double
類型然后再傳遞進(jìn)去,也不會(huì)出現(xiàn)類型沖突的問題cout << Add((double)a1, d2) << endl;
- 顯式實(shí)例化:在函數(shù)名后的<>中指定模板參數(shù)的實(shí)際類型
- 除了上面這種手動(dòng)強(qiáng)轉(zhuǎn)的措施,還有一種辦法就是我們自己進(jìn)行【顯式實(shí)例化】,如何你還有印象的話,可以翻上看看匯編,其實(shí)編譯器在底層就是轉(zhuǎn)換為了這種形式
// 顯式實(shí)例化,用指定類型實(shí)例化
cout << Add<int>(a1, d2) << endl;
cout << Add<double>(a1, d2) << endl;
雖然上面我們介紹了兩種處理方式,但是對(duì)于某些場(chǎng)景來說,卻只能進(jìn)行【顯式實(shí)例化】
- 例如我在下面寫了一個(gè)函數(shù)模版,形參部分并不是模版參數(shù),而是普通的自定義類型,之后返回值才是,那此時(shí)我們就無法通過傳參來指定這個(gè)【T】的類型,只能有外部在調(diào)用這個(gè)模版的時(shí)候顯示指定
template<class T> T* Alloc(int n) { return new T[n]; }
- 例如下面的這些,我們想開什么數(shù)據(jù)類型的空間,只需要顯示指定類型即可
// 有些函數(shù)無法自動(dòng)推,只能顯示實(shí)例化 double* p1 = Alloc<double>(10); float* p1 = Alloc<float>(20); int* p2 = Alloc<int>(30);
5、模板參數(shù)的匹配原則
① 一個(gè)非模板函數(shù)可以和一個(gè)同名的函數(shù)模板同時(shí)存在,而且該函數(shù)模板還可以被實(shí)例化為這個(gè)非模板函數(shù)
- 可以看到,我在下面寫了一個(gè)專門處理int的加法函數(shù),為普通的函數(shù),又寫了一個(gè)函數(shù)模版,它們是可以進(jìn)行共存的,在進(jìn)行普通傳參的時(shí)候,就會(huì)去調(diào)用這個(gè)普通的Add函數(shù);若是顯式指明了類型的話,就會(huì)去調(diào)用這個(gè)函數(shù)模版讓編譯器生成對(duì)應(yīng)的函數(shù)
// 專門處理int的加法函數(shù) int Add(int left, int right) { return left + right; } // 通用加法函數(shù) template<class T> T Add(T left, T right) { return left + right; } int main(void) { Add(1, 2); Add<int>(1, 2); return 0; }
②?對(duì)于非模板函數(shù)和同名函數(shù)模板,如果其他條件都相同,在調(diào)動(dòng)時(shí)會(huì)優(yōu)先調(diào)用非模板函數(shù)而不會(huì)從該模板產(chǎn)生出一個(gè)實(shí)例。如果模板可以產(chǎn)生一個(gè)具有更好匹配的函數(shù), 那么將選擇模板
- 也是和上面類似的代碼,不過對(duì)于函數(shù)模版這一塊我使用到了兩個(gè)模版參數(shù),就是為了匹配多種數(shù)據(jù)類型
// 專門處理int的加法函數(shù)
int Add(int left, int right)
{
return left + right;
}
// 通用加法函數(shù)
template<class T1, class T2>
T1 Add(T1 left, T2 right)
{
return left + right;
}
int main(void)
{
Add(1, 2);
Add(1, 2.2);
return 0;
}
- 觀察調(diào)試結(jié)果我們可以發(fā)現(xiàn)Add(1, 2)優(yōu)先去調(diào)了普通的加法函數(shù),因?yàn)閭鬟f進(jìn)去的是兩個(gè)【int】類型的參數(shù),完全吻合;但是呢對(duì)于第二個(gè)Add(1, 2.2)來說,卻去調(diào)用了函數(shù)模版,因?yàn)榈诙€(gè)參數(shù)是【double】類型,普通的函數(shù)它也接不住呀,此時(shí)模版參數(shù)就可以根據(jù)這個(gè)類型來進(jìn)行一個(gè)自動(dòng)推導(dǎo)
③ 模板函數(shù)不允許自動(dòng)類型轉(zhuǎn)換,但普通函數(shù)可以進(jìn)行自動(dòng)類型轉(zhuǎn)換
- 首先對(duì)于普通函數(shù)而言很好理解,看到print函數(shù)的形參所給的類型為【int】,但是在外界傳入了一個(gè)【double】類型的數(shù)值,如果你學(xué)習(xí)過 隱式類型轉(zhuǎn)換 的話,就可以知道這個(gè)浮點(diǎn)數(shù)傳入的話會(huì)發(fā)生一個(gè)轉(zhuǎn)換,這就叫做【自動(dòng)類型轉(zhuǎn)換】
// 普通函數(shù),允許自動(dòng)類型轉(zhuǎn)換 void print(int value) { std::cout << "Integer: " << value << std::endl; } int main() { print(3); print(3.14); return 0; }
- 但是呢,對(duì)于模版函數(shù)來說是無法進(jìn)行自動(dòng)類型轉(zhuǎn)換的,例如下面這個(gè),我為這個(gè)函數(shù)模版定義了一個(gè)模版參數(shù),但是在外界進(jìn)行傳遞的時(shí)候卻傳遞進(jìn)來兩種數(shù)據(jù)類型,為【int】或【double】,那么一個(gè)模版參數(shù)T就使得編譯器無法去進(jìn)行自動(dòng)推導(dǎo)
template <class T> void print(T a, T b) { cout << a << " " << b << endl; } int a = 1; double b = 1.11; print(a, b);
- 這個(gè)其實(shí)我們?cè)谏厦嬉仓v到過,再來回顧一下,改進(jìn)的方法有兩種,一個(gè)是【強(qiáng)制類型轉(zhuǎn)換】,還記得罰站的事情嗎;另一個(gè)則是【顯式實(shí)例化】,還記得我們看的匯編嗎
// 強(qiáng)制類型轉(zhuǎn)換 print(a, (int)b); print((double)a, b); // 顯式實(shí)例化 print<int>(a, b); print<double>(a, b);
- 其實(shí)還有一種改進(jìn)的方法,那就是增加模版參數(shù),因?yàn)橐粋€(gè)模版參數(shù)接收兩種類型是無法進(jìn)行自動(dòng)推導(dǎo)的,此時(shí)若是有兩個(gè)模版參數(shù)的話就可以接收兩種類型了,不會(huì)出現(xiàn)錯(cuò)誤
三、類模版
講完了函數(shù)模版后,我們?cè)賮碚f說類模版,也就是對(duì)一個(gè)類來說,也是可以定義為一個(gè)模版的
1、類模板的定義格式
- 首先來看到的就是其定義格式,函數(shù)模版加在函數(shù)上,那對(duì)于類模版的話就是加在類上
template<class T1, class T2, ..., class Tn> class 類模板名 { // 類內(nèi)成員定義 };
我們以下面這個(gè)Stack類為例來進(jìn)行講解
- 如果你學(xué)習(xí)了模版的相關(guān)知識(shí)后,一定會(huì)覺得這個(gè)類的限制性太大了,只能初始化一個(gè)具有整型數(shù)據(jù)的棧,如果此時(shí)我想要放一些浮點(diǎn)型的數(shù)據(jù)進(jìn)來的話也做不到
typedef int DataType; class Stack { public: Stack(size_t capacity = 3) { _array = (DataType*)malloc(sizeof(DataType) * capacity); if (NULL == _array) { perror("malloc申請(qǐng)空間失敗!!!"); return; } _capacity = capacity; _size = 0; } void Push(DataType data) { // CheckCapacity(); _array[_size] = data; _size++; } // 其他方法... ~Stack() { if (_array) { free(_array); _array = NULL; _capacity = 0; _size = 0; } } private: DataType* _array; int _capacity; int _size; };
?? 如果沒有模版技術(shù)的話你會(huì)如何去解決這個(gè)問題呢?很簡(jiǎn)單那就是定義多個(gè)類
- ?這是我們同學(xué)最擅長(zhǎng)的事,CV一下兩個(gè)棧就有了,
StackInt
存放整型數(shù)據(jù),StackDouble
存放浮點(diǎn)型數(shù)據(jù)
但是本文我們重點(diǎn)要講解的就是【模版技術(shù)】,技術(shù)界有一句話說得好 “不要重復(fù)造輪子”
- 下面就是使用模版去定義的一個(gè)類,簡(jiǎn)稱【模板類】,不限制死數(shù)據(jù)類型,將所有的DataType都改為【T】
template<class T> class Stack { public: Stack(size_t capacity = 3) { _array = (DataType*)malloc(sizeof(DataType) * capacity); if (NULL == _array) { perror("malloc申請(qǐng)空間失敗!!!"); return; } _capacity = capacity; _size = 0; } void Push(T data) { // CheckCapacity(); _array[_size] = data; _size++; } // 其他方法... ~Stack() { if (_array) { free(_array); _array = NULL; _capacity = 0; _size = 0; } } private: T* _array; int _capacity; int _size; };
- 但是呢就上面這樣其實(shí)并不是最規(guī)范的寫法,還記得我們?cè)趯W(xué)習(xí)C++類和對(duì)象講到過一個(gè)類要聲明和定義分離,那對(duì)于模板類也同樣適用,我們馬上來看看
template<class T> // 類模版 class Stack { public: Stack(size_t capacity = 3); void Push(T data); ~Stack(); private: T* _array; int _capacity; int _size; };
- 不過呢可以看到直接像我們之前那樣去進(jìn)行類外定義似乎行不通,說
缺少類模版“Stack”的參數(shù)列表
,因?yàn)檫@個(gè)成員函數(shù)內(nèi)部也使用到了模版參數(shù)T,那么這個(gè)函數(shù)也要變?yōu)楹瘮?shù)模版才行 - ?但是在加上這個(gè)模版參數(shù)后,似乎還是有問題,::這個(gè)操作符我們?cè)贑++命名空間中有提到過,叫做【域作用限定符】,是我們使用命名空間去訪問特定成員變量或成員函數(shù)時(shí)使用的,對(duì)于類來說它一定要是一個(gè)類名
- 這里要強(qiáng)調(diào)一點(diǎn)的是對(duì)于普通類來說類名和類型是一樣的, 像構(gòu)造函數(shù),它的函數(shù)名就是類名;可是對(duì)于模板類來說是不一樣,類名和類型不一樣,這里Stack只是這個(gè)模版類的類名罷了,但我們現(xiàn)在需要的是類型,此處就想到了我們?cè)谏厦嫠鶎W(xué)的【顯式實(shí)例化】,這個(gè)模板類的類型即為Stack<T>
- 以下即是對(duì)這個(gè)模版類中的成員函數(shù)在類外實(shí)現(xiàn)所需要變化成的模版函數(shù)
template<class T>
Stack<T>::Stack(size_t capacity)
{
_array = new T(capacity);
_capacity = capacity;
_size = 0;
}
- 那對(duì)于其他函數(shù)也是一致,均需要將它們定義為模版函數(shù),此時(shí)我們可以意識(shí)到一點(diǎn)的是對(duì)于模版函數(shù)來說,其模版參數(shù)的作用域就在這個(gè)函數(shù)內(nèi)部,出了這個(gè)函數(shù)就無法使用了, 所以可以看到每個(gè)函數(shù)前面都需要其對(duì)應(yīng)的模版參數(shù);而且對(duì)于模版類來說也是同理,只在這個(gè)類內(nèi)起作用,即到收括號(hào)};為止,我們知道對(duì)于一個(gè)類來說也算是一個(gè)獨(dú)立的空間,成員函數(shù)是不包含在類內(nèi)的,所以其在類外進(jìn)行定義的時(shí)候就需要再重新定義模版參數(shù)
template<class T> // 每個(gè)函數(shù)或類前都要加上其對(duì)應(yīng)的模版參數(shù) void Stack<T>::Push(T data) { // CheckCapacity(); _array[_size] = data; _size++; } template<class T> Stack<T>::~Stack() { if (_array) { free(_array); _array = NULL; _capacity = 0; _size = 0; } }
2、類模板的實(shí)例化
清楚了什么是類模版之后,我們就將上面的這個(gè)Stack類模版給實(shí)例化出來吧
?? 類模板實(shí)例化與函數(shù)模板實(shí)例化不同,類模板實(shí)例化需要在類模板名字后跟<>,然后將實(shí)例化的類型放在<>中即可,類模板名字不是真正的類,而實(shí)例化的結(jié)果才是真正的類
- 可以看到因?yàn)槲覀儗⑦@個(gè)類定義為了類模版,此時(shí)便可以去初始化不同數(shù)據(jù)類型的棧了,上面說到過Stack是類名,但是像Stack<int>、Stack<double>這些都是它的類型
int main(void) { Stack<int> s1; // int Stack<double> s2; // double Stack<char> s3; // char return 0; }
四、總結(jié)與提煉
最后我們來總結(jié)一下本文所學(xué)習(xí)的內(nèi)容??
- 首先我們了解了什么是泛型編程的思想,通過曹植的《洛神賦》到【活字印刷術(shù)】,我們體會(huì)到了有一個(gè)通用模版的重要性,于是就引申出了C++中的模版這一個(gè)概念,對(duì)于模版呢,其分為 函數(shù)模版 和 類模版
- 首先呢我們介紹了什么是【函數(shù)模版】,新學(xué)習(xí)了一個(gè)關(guān)鍵字叫做template,用它再配合模版參數(shù)就可以去定義出一個(gè)函數(shù)模版,有了它,我們?cè)趯懸恍┫嗤愋秃瘮?shù)的時(shí)候就無需去進(jìn)行重復(fù)的CV操作了,在通過匯編觀察函數(shù)模版的原理后,清楚了我們只需要傳入不同的類型,此時(shí)模版參數(shù)就會(huì)去進(jìn)行一個(gè)自動(dòng)類型推導(dǎo),從而產(chǎn)生不同的函數(shù)。函數(shù)模版定義好后還要對(duì)其實(shí)例化才能繼續(xù)使用,但此時(shí)要注意的一點(diǎn)是如果傳遞進(jìn)去的類型個(gè)數(shù)與模版參數(shù)的個(gè)數(shù)不匹配的話,其就無法完成自動(dòng)類型推導(dǎo),因?yàn)檫@會(huì)產(chǎn)生一個(gè)歧義。所以想要真正學(xué)好模版,這點(diǎn)是一定要搞清楚的?。?!
- 接下去呢我們又學(xué)習(xí)了【類模版】,沒想到吧,類也可以變成一個(gè)模版,以Stack類為例,對(duì)于類模版而言,其類名和類型與普通類是不一樣的,這點(diǎn)要注意了,尤其體現(xiàn)在類的成員函數(shù)放在類外進(jìn)行定義的時(shí)候,也要將其定義為函數(shù)模版,函數(shù)名前面指明其類型,這才不會(huì)出問題。有了類模版之后,我們?nèi)ワ@式實(shí)例化不同的數(shù)據(jù)類型后也可以讓模版參數(shù)去做一個(gè)自動(dòng)類型推導(dǎo)從而得到不同數(shù)據(jù)類型的棧
?總而言之,模版是C++的一個(gè)亮點(diǎn)所在,也是學(xué)習(xí)STL的基礎(chǔ),望讀者扎實(shí)掌握??
以上就是本文要介紹的所有內(nèi)容,感謝您的閱讀??
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~文章來源:http://www.zghlxwxcb.cn/news/detail-555090.html
此文借鑒與https://blog.csdn.net/Fire_Cloud_1/article/details/131611593文章來源地址http://www.zghlxwxcb.cn/news/detail-555090.html
到了這里,關(guān)于感受C++模版的所帶來的魅力的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!