C++超詳細講解泛型
1.了解泛型編程
就好比活字印刷術(shù),可以靈活調(diào)整印刷的板塊和內(nèi)容,比只能固定印刷某一個內(nèi)容的雕版印刷術(shù)效率更高,也讓印刷術(shù)由此得到了更廣泛的應用。
在C++中,函數(shù)重載和模板的出現(xiàn),讓泛型編程得到了實際的應用。其中模板,就是類似活字印刷術(shù)一樣的存在。
2.函數(shù)模板
八八了那么多沒用的,讓我們來看看函數(shù)模板的語法實現(xiàn)吧
2.1簡單示例
下面是一個最簡單的交換函數(shù)的例子,通過標明模板參數(shù)T
,讓編譯器自動識別函數(shù)傳參,并調(diào)用出不同的函數(shù)
template<typename T> void Swap(T& left,T& right) { T temp = left; left = right; right = temp; }
其中,typename
是定義模板的關(guān)鍵字,我們可以使用class
來替代,但不能使用struct
可以看到,編譯器成功調(diào)用了Swap函數(shù),交換了int類型和double類型
2.2多個模板參數(shù)
如果我們嘗試把int和double同時傳參給這個函數(shù),會發(fā)生什么呢?
編譯器會報錯,表示模板參數(shù)T不明確
這時候我們有幾種解決方法
首先是將double強轉(zhuǎn)為int(反過來亦可)
你會發(fā)現(xiàn)還是不行,那是因為強轉(zhuǎn)并不支持用double引用int。所以我們把函數(shù)傳參中的引用去掉,即可正常調(diào)用這個函數(shù)(暫且不提傳引用和傳值的區(qū)別)
使用多個模板參數(shù)
和函數(shù)傳參類似,我們也可以設(shè)置多個模板參數(shù)
在下圖中,我使用typeid
關(guān)鍵字來打印模板參數(shù)T1和T2的類型。
使用typeid
需要包含頭文件#include <typeinfo>
可以看到,實際上函數(shù)在調(diào)用這個模板的時候,已經(jīng)實例化了這個函數(shù)(即替換模板參數(shù)為正確參數(shù)類型)這時候在后臺處理的時候,其實Show函數(shù)已經(jīng)實例化為了下面這個樣子
void Show(int left, double right) { cout << typeid(left).name() << endl; cout << typeid(right).name() << endl; }
2.3模板實例化
上面的方式,是編譯器自動幫我們實例化模板參數(shù)。在實際使用中,我們還可以自己指定實例化為什么類型
- 利用強制類型轉(zhuǎn)換
- 使用
<int>
直接指定實例化為int類型
使用第二種方式的時候,編譯器會對另外一個不匹配的參數(shù)進行隱式類型轉(zhuǎn)換。如果轉(zhuǎn)換不成功,則會報錯。
另外注意的是,函數(shù)模板參數(shù)T同樣可以用來作為返回值,但是不能通過返回值來推斷參數(shù)T的類型。比如下面這個函數(shù),我們在使用的時候就需要直接指定模板參數(shù)T,而不能寫一個int* ptr=test(10)
讓編譯器通過“返回值是int*
接收的,所以函數(shù)模板參數(shù)T是int”來推斷。
template<typename T> T* test(int num) { return new T[num]; }
函數(shù)模板支持給予參數(shù)缺省值
當一個參數(shù)不確定的時候,函數(shù)模板是支持給予缺省值的
template<typename T=char> T* test(int num) { return new T[num]; }
比如這樣,當我們沒有直接指定的時候,編譯器就會將T作為char類型,返回一個num大小的char(一個字節(jié))的空間
注意:當有多個模板參數(shù)時,缺省值需要從右往左給
函數(shù)模板的傳參也支持缺省值
template<typename T1> void Add(T1 left, T1 right=10) { cout << "Add temp "<<typeid(left).name() << " " << typeid(right).name() << endl; cout << left + right << endl << endl; } int main() { int a=1; Add(a); }
在這種情況下,編譯器會正確調(diào)用該函數(shù)模板
2.4模板和普通函數(shù)同時存在
以Add函數(shù)為例,在函數(shù)模板存在的同時,我們還可以單獨寫一個int類型的add函數(shù)。這都歸功于函數(shù)重載的存在。
同時,我們還可以使用<int>
來指定函數(shù)模板重載為已存在的Add函數(shù)。因為本質(zhì)上這兩個函數(shù)是不同的,并不會沖突。
函數(shù)在調(diào)用的時候,首先會去調(diào)用已經(jīng)存在的函數(shù)。當參數(shù)和已存在的函數(shù)不匹配時,才會調(diào)用函數(shù)模板
2.5函數(shù)模板不支持定義和聲明分離
一般情況下,我們都會在頭文件中生命函數(shù),在另外一個源文件中定義函數(shù)。
但是模板是不支持這么做的!編譯器會報錯 鏈接錯誤
error LNK2019:無法解析的外部符號……
所以我們需要將函數(shù)模板的聲明和定義放在一個頭文件中。在部分使用場景,會使用.hpp
來表示這個頭文件是包含了函數(shù)定義的(即.h和.cpp
的集合體)。需要注意,這并不是一個硬性要求,你也可以直接使用.h
,并將聲明和定義放入其中。
這是為什么呢?
因為單獨的.h
聲明會在源文件頂部展開,而此時函數(shù)模板正常推演參數(shù),但編譯器并沒有找到函數(shù)的實現(xiàn),即這是一個沒有地址的函數(shù)。從而導致編譯器找不到函數(shù)的地址,產(chǎn)生了符號表的鏈接錯誤
有無解決辦法?
其實是有的,我們可以在模板函數(shù)定義的.cpp
中對我們需要使用的函數(shù)進行顯式實例化指定
//頭文件 //聲明 template<typename T1> void Add(T1 left, T1 right); //源文件 //定義 template<typename T1> void Add(T1 left, T1 right) { cout << left + right << endl << endl; } //在源文件中顯式實例化 template void Add<int>(int left, int right); template void Add<double>(double left, double right);
顯式實例化需要對我們要用的所有函數(shù)進行實例化,比如你需要用double類型,只顯示實例化了int類型是不行的,依舊會報錯。
這樣感覺非常多余……對吧!所以還是老老實實把聲明和定義放在同一個文件里面吧!
3.類模板
類模板的基本形式如下,這里作為一個小區(qū)分,我用class
來當作模板參數(shù)名。實際上typename
也是可以的
template<class T1, class T2, ...>class 類模板名{<!--{C}%3C!%2D%2D%20%2D%2D%3E-->// 類內(nèi)成員定義}; template<class T1, class T2, ...> class 類模板名 { // 類內(nèi)成員定義 };
3.1簡單示例
下面用一個非常簡單的順序表代碼來演示一下類模板
template<class T> class List { public: List(int capacity = 10) : _a(new T[capacity]) , _size(0) , _capa(capacity) {} ~List(); T& operator[](int pos) { assert(pos < _size); return _a[pos]; } private: T* _a; int _size; int _capa; }; //類模板中函數(shù)放在類外進行定義時,需要加模板參數(shù)列表 template <class T> List<T>::~List() { delete[] _a; _size = _capa = 0; }
可以看到,通過顯式實例化的方式,我們成功讓這個類模板變成了兩個不同類型的順序表
3.2成員函數(shù)聲明和定義分離
其中需要注意的是析構(gòu)函數(shù),聲明和定義分離的時候(同一文件),在定義的時候也需要加上模板參數(shù)
//類模板中函數(shù)放在類外進行定義時,需要加模板參數(shù)列表 template <class T> List<T>::~List() { delete[] _a; _size = _capa = 0; }
個人覺得這樣也非常麻煩,既然模板最好是聲明和定義放在同一個文件,那還不如直接將類的成員函數(shù)直接定義到類內(nèi)部。多省事!
如果是聲明和定義放在不同文件中,顯式實例化方式如下
template class List <int>; template class List <double>;
需要什么類型的類,就得實例化這個類型。
到此這篇關(guān)于C++超詳細講解泛型的文章就介紹到這了,更多相關(guān)C++泛型內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
用while判斷輸入的數(shù)字是否回文數(shù)的簡單實現(xiàn)
這篇文章主要介紹了用while判斷輸入的數(shù)字是否回文數(shù)的簡單實現(xiàn),需要的朋友可以參考下2014-02-02C語言中字符串和數(shù)字的相互轉(zhuǎn)換實現(xiàn)代碼
以下是對C語言中字符串和數(shù)字的相互轉(zhuǎn)換實現(xiàn)代碼進行了分析介紹,需要的朋友可以參考下2013-07-07C++中用new創(chuàng)建二維數(shù)組和指針數(shù)組實例代碼
這篇文章主要介紹了C++中用new創(chuàng)建二維數(shù)組和指針數(shù)組實例代碼,非常不錯,具有參考借鑒價值,需要的朋友參考下2017-03-03C語言游戲必備:光標定位與顏色設(shè)置的實現(xiàn)方法
本篇文章是對c語言中光標定位與顏色設(shè)置的方法進行了詳細的分析介紹,需要的朋友參考下2013-05-05