C++模板Template詳解及其作用介紹
1. 模板
首先模板分為函數(shù)模板和類模板
想到模板,就會(huì)聯(lián)想到泛型編程
泛型編程:編寫與類型無關(guān)的通用代碼,是代碼復(fù)用的一種手段。模板是泛型編程的基礎(chǔ)。
網(wǎng)圖:
在之前,我們已經(jīng)知道了函數(shù)重載
還是那一個(gè)例子 Swap函數(shù)交換 int double char
哪怕是函數(shù)重載,我們也要寫三個(gè),但是如果有了模板,我們只需要:
告訴編譯器一個(gè)模板,讓編譯器根據(jù)不同的類型利用該模板來生成代碼
2. 函數(shù)模板
2.1 函數(shù)模板概念
函數(shù)模板代表了一個(gè)函數(shù)家族,該函數(shù)模板與類型無關(guān),在使用時(shí)被參數(shù)化,根據(jù)實(shí)參類型產(chǎn)生 函數(shù)的特定類型版本。(上面的圖就是一個(gè)函數(shù)模板的例子)
2.2 函數(shù)模板格式
template<typename T1, typename T2,......,typename Tn>
返回值類型 函數(shù)名 ( 參數(shù)列表 ){}
template<typename T> void Swap( T& left, T& right) { T temp = left; left = right; right = temp; }
注意: typename 是 用來定義模板參數(shù) 關(guān)鍵字 , 也可以使用 class( 切記:不能使用 struct 代替 class)
2.3 函數(shù)模板原理
函數(shù)模板是一個(gè)藍(lán)圖,它本身并不是函數(shù),是編譯器用使用方式產(chǎn)生特定具體類型函數(shù)的模具。 所以其實(shí)模板就是將本來應(yīng)該我們做的重復(fù)的事情交給了編譯器。 簡(jiǎn)單說就是本來我們應(yīng)該多去寫的Swap的重復(fù)工作去給編譯器做了 網(wǎng)圖:
在編譯器編譯階段 ,對(duì)于模板函數(shù)的使用, 編譯器需要根據(jù)傳入的實(shí)參類型來推演生成對(duì)應(yīng)類型 的函數(shù) 以供調(diào)用。比如: 當(dāng)用 double 類型使用函數(shù)模板時(shí),編譯器通過對(duì)實(shí)參類型的推演,將 T 確定為 double 類型,然后產(chǎn)生一份專門處理 double 類型的代碼 ,對(duì)于字符類型也是如此。
2.4 函數(shù)模板的實(shí)例化
用不同類型的參數(shù)使用函數(shù)模板時(shí) ,稱為函數(shù)模板的 實(shí)例化 。模板參數(shù)實(shí)例化分為: 隱式實(shí)例化 和顯式實(shí)例化 。
1. 隱式實(shí)例化:讓編譯器根據(jù)實(shí)參推演模板參數(shù)的實(shí)際類型
2. 顯式實(shí)例化:在函數(shù)名后的 <> 中指定模板參數(shù)的實(shí)際類型
2.5 模板參數(shù)的匹配原則
1. 一個(gè)非模板函數(shù)可以和一個(gè)同名的函數(shù)模板同時(shí)存在,而且該函數(shù)模板還可以被實(shí)例化為這 個(gè)非模板函數(shù)
就比如一個(gè)模板的Add和一個(gè)自己實(shí)現(xiàn)的Add可以一起存在
然后:
void Test ()
{
Add ( 1 , 2 ); // 與非模板函數(shù)匹配,編譯器不需要特化
Add < int > ( 1 , 2 ); // 調(diào)用編譯器特化的 Add 版本
}
2. 對(duì)于非模板函數(shù)和同名函數(shù)模板,如果其他條件都相同,在調(diào)動(dòng)時(shí)會(huì)優(yōu)先調(diào)用非模板函數(shù)而 不會(huì)從該模板產(chǎn)生出一個(gè)實(shí)例。如果模板可以產(chǎn)生一個(gè)具有更好匹配的函數(shù), 那么將選擇模板。
簡(jiǎn)單說會(huì)先找自己實(shí)現(xiàn)的有沒有,沒有就去看模板能不能實(shí)例化一個(gè)。
3. 模板函數(shù)不允許自動(dòng)類型轉(zhuǎn)換,但普通函數(shù)可以進(jìn)行自動(dòng)類型轉(zhuǎn)換
2.6聲明定義分離
也可以聲明定義分離
不同的是模板參數(shù)聲明定義都要給
3. 類模板
3.1 類模板格式
template<class T1, class T2, ..., class Tn> class 類模板名 { // 類內(nèi)成員定義 };
這里就習(xí)慣用上class,上面的函數(shù)模板是typename
3.2 類模板的實(shí)例化
類模板實(shí)例化與函數(shù)模板實(shí)例化不同, 類模板實(shí)例化需要在類模板名字后跟 <> ,然后將實(shí)例化的 類型放在 <> 中即可,類模板名字不是真正的類,而實(shí)例化的結(jié)果才是真正的類 。
雖然有警告,但是為了測(cè)試,問題不大。我們可以發(fā)現(xiàn)這里是創(chuàng)建了兩個(gè)對(duì)象的,因?yàn)樗麄冊(cè)诟髯缘哪挲g和身高打印都是有所區(qū)別的(有無小數(shù))
在這里 Student 這個(gè)類是一個(gè)模板,我們用這個(gè)模板創(chuàng)建了兩個(gè)對(duì)象 分別是張三和李四
注意:Student 不是具體的類,是編譯器根據(jù)被實(shí)例化的類型生成具體類的模具 PS:上面是用的Init,習(xí)慣還沒改過來,大家還是用構(gòu)造函數(shù)比較好
3.3 類模板中函數(shù)放在類外進(jìn)行定義時(shí)
需要加模板參數(shù)列表
4. 模板分離編譯
4.1 什么是分離編譯
一個(gè)程序(項(xiàng)目)由若干個(gè)源文件共同實(shí)現(xiàn),而每個(gè)源文件單獨(dú)編譯生成目標(biāo)文件,最后將所有目標(biāo)文件鏈接起來形成單一的可執(zhí)行文件的過程稱為分離編譯模式。
4.2 模板的分離編譯
假如有以下場(chǎng)景,模板的聲明與定義分離開,在頭文件中進(jìn)行聲明,源文件中完成定義:
// a.h template<class T> T Add(const T& left, const T& right); // a.cpp template<class T> T Add(const T& left, const T& right) { return left + right; } // main.cpp #include"a.h" int main() { Add(1, 2); Add(1.0, 2.0); return 0; }
我們開始運(yùn)行
問題:會(huì)出現(xiàn)鏈接錯(cuò)誤。
原因:首先程序運(yùn)行是要預(yù)處理,編譯匯編和鏈接。對(duì)于頭文件的內(nèi)容,a.cpp .i .s .o模板都是空的,因?yàn)榫幾g器下不了手,不知道T是啥。(模板是在編譯階段處理,不是預(yù)處理)
main.cpp 里面因?yàn)橹挥新暶?,所以call是不知道地址的
然后鏈接的時(shí)候,因?yàn)閍.cpp是沒有生成對(duì)應(yīng)的函數(shù)的(因?yàn)橹癟不知道),所以鏈接的時(shí)候會(huì)發(fā)生鏈接錯(cuò)誤。
簡(jiǎn)單說就是編譯的時(shí)候經(jīng)過模板的定義了但是因?yàn)門不知道所以不會(huì)生成對(duì)應(yīng)的匯編代碼,導(dǎo)致最后main.cpp里面要調(diào)用的時(shí)候并沒有生成對(duì)應(yīng)的函數(shù)所以會(huì)出現(xiàn)鏈接錯(cuò)誤。
解決:
- 放在一個(gè)名為 .hpp 的文件,也是就是這個(gè)文件是.h和.cpp的合體,寓意更好。直接.h也可以哈。(推薦)
- 對(duì)于上面的原因?qū)ΠY下藥,因?yàn)橹挥新暶鳑]有生成對(duì)應(yīng)的定義,所以我們直接在 a.cpp 文件 顯示實(shí)例化指定在定義的下面加上:
template int Add<int>(int& left, int& right); template double Add<double>(double& left, double& right);
為什么:
但是為什么放在一起就沒有鏈接錯(cuò)誤了?
因?yàn)槁暶骱投x放在一起,調(diào)用函數(shù)的時(shí)候直接實(shí)例化call地址去了,所以不報(bào)錯(cuò)并不是因?yàn)殒溄幽苷业?,而是根本沒有去找,直接call地址了。
5. 缺省值與返回值
也可以有缺省值(半/全),但是必須是從右往左缺?。惐群瘮?shù)),因?yàn)閭鲄⑹菑淖笸覀鞯?/p>
也可以模板做返回值
6. 總結(jié)
優(yōu)點(diǎn):
1. 模板復(fù)用了代碼,節(jié)省資源,更快的迭代開發(fā), C++ 的標(biāo)準(zhǔn)模板庫(kù) (STL) 因此而產(chǎn)生
2. 增強(qiáng)了代碼的靈活性
缺陷:
1. 模板會(huì)導(dǎo)致代碼膨脹問題,也會(huì)導(dǎo)致編譯時(shí)間變長(zhǎng)
2. 出現(xiàn)模板編譯錯(cuò)誤時(shí),錯(cuò)誤信息非常凌亂,不易定位錯(cuò)誤
到此這篇關(guān)于C++模板Template詳解及其作用介紹的文章就介紹到這了,更多相關(guān)C++模板內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++文件關(guān)鍵詞快速定位出現(xiàn)的行號(hào)實(shí)現(xiàn)高效搜索
這篇文章主要為大家介紹了C++文件關(guān)鍵詞快速定位出現(xiàn)的行號(hào)實(shí)現(xiàn)高效搜索,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10Cocos2d-x中使用CCScrollView來實(shí)現(xiàn)關(guān)卡選擇實(shí)例
這篇文章主要介紹了Cocos2d-x中使用CCScrollView來實(shí)現(xiàn)關(guān)卡的選擇實(shí)例,本文在代碼中用大量注釋講解了CCScrollView的使用,需要的朋友可以參考下2014-09-09C++中運(yùn)算符 &和&&、|和|| 的詳解及區(qū)別
這篇文章主要介紹了C++中運(yùn)算符 &和&&、|和|| 的詳解及區(qū)別的相關(guān)資料,這里舉例說明該如何區(qū)別他們的不同,需要的朋友可以參考下2016-11-11C++?Socket實(shí)現(xiàn)TCP與UDP網(wǎng)絡(luò)編程
本文主要介紹了C++?Socket實(shí)現(xiàn)TCP與UDP網(wǎng)絡(luò)編程,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01C語言數(shù)據(jù)結(jié)構(gòu)之單鏈表的查找和建立
鏈表是一種物理存儲(chǔ)結(jié)構(gòu)上非連續(xù)、非順序的存儲(chǔ)結(jié)構(gòu),數(shù)據(jù)元素的邏輯順序是通過鏈表中的指針鏈接次序?qū)崿F(xiàn)的。本文將和大家一起聊聊C語言中單鏈表的查找和建立,感興趣的可以學(xué)習(xí)一下2022-09-09