1. 前言
之前我們學(xué)習(xí)了函數(shù)重載,讓我們?cè)趯?xiě)相似函數(shù)的時(shí)候非常方便,但函數(shù)重載還有很多不足的地方,比如,每次寫(xiě)相似函數(shù)的時(shí)候,都要我們重新重載一個(gè)邏輯、代碼幾乎一樣的函數(shù),這就導(dǎo)致了我們的效率變低,所以我們今天來(lái)學(xué)習(xí)C++模板的相關(guān)知識(shí)點(diǎn),學(xué)習(xí)完模板之后,我們就可以很好的解決這些問(wèn)題。
2. 泛型編程
以前我們要實(shí)現(xiàn)一個(gè)通用的交換函數(shù)時(shí)是怎么做的呢?我們利用了函數(shù)重載,把可能用到的函數(shù)都重載出來(lái)。
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ù)重載雖然可以做到,但是有幾個(gè)不足的地方:
1.重載的函數(shù)僅僅是類(lèi)型不同,代碼復(fù)用率比較低,只要有新類(lèi)型出現(xiàn)時(shí),就需要用戶(hù)自己增加對(duì)應(yīng)的函數(shù)
2.代碼的可維護(hù)性比較低,一個(gè)出錯(cuò)可能所有的重載均出錯(cuò)
那么我們?cè)撊绾谓鉀Q這個(gè)問(wèn)題呢?
如果在C++中,能夠存在一個(gè)模具,通過(guò)給這個(gè)模具中填充不同材料(類(lèi)型),來(lái)獲得不同材料的鑄件(即生成具體類(lèi)型的代碼)這樣就會(huì)讓我們大幅提高效率。
泛型編程:
編寫(xiě)與類(lèi)型無(wú)關(guān)的通用代碼,是代碼復(fù)用的一種手段。
模板是泛型編程的基礎(chǔ)。模板又分為函數(shù)模板和類(lèi)模板。
3. 函數(shù)模板
概念:
函數(shù)模板代表了一個(gè)函數(shù)家族,該函數(shù)模板與類(lèi)型無(wú)關(guān),在使用時(shí)被參數(shù)化,根據(jù)實(shí)參類(lèi)型產(chǎn)生函數(shù)的特定類(lèi)型版本。
格式:
template<typename T1, typename T2,…,typename Tn>
返回值類(lèi)型 函數(shù)名(參數(shù)列表) {}
注意:
typename是用來(lái)定義模板參數(shù)關(guān)鍵字,也可以使用class。
typename后面類(lèi)型名字T是隨便取的。
//template<typename T>
template<class T>
void Swap(T& left, T& right)
{
T tmp = left;
left = right;
right = tmp;
}
3.1 函數(shù)模板的原理
函數(shù)模板是一個(gè)藍(lán)圖,它本身并不是函數(shù),是編譯器用使用方式產(chǎn)生特定具體類(lèi)型函數(shù)的模具。所以其實(shí)模板就是將本來(lái)應(yīng)該我們做的重復(fù)的事情交給了編譯器。
在編譯器編譯階段,對(duì)于模板函數(shù)的使用,編譯器需要根據(jù)傳入的實(shí)參類(lèi)型來(lái)推演生成對(duì)應(yīng)類(lèi)型的函數(shù)以供調(diào)用。
比如:當(dāng)用double類(lèi)型使用函數(shù)模板時(shí),編譯器通過(guò)對(duì)實(shí)參類(lèi)型的推演,將T確定為double類(lèi)型,然后產(chǎn)生一份專(zhuān)門(mén)處理double類(lèi)型的代碼,對(duì)于字符類(lèi)型也是如此。
3.2 函數(shù)模板的實(shí)例化
用不同類(lèi)型的參數(shù)使用函數(shù)模板時(shí),稱(chēng)為函數(shù)模板的實(shí)例化。模板參數(shù)實(shí)例化分為:隱式實(shí)例化和顯式實(shí)例化。
隱式實(shí)例化:讓編譯器根據(jù)實(shí)參推演模板參數(shù)的實(shí)際類(lèi)型
顯式實(shí)例化:在函數(shù)名后的<>中指定模板參數(shù)的實(shí)際類(lèi)型
template<typename T>
T Add(const T& x, const T& y)
{
return x + y;
}
int main()
{
int a = 1, b = 2;
double c = 1.1, d = 2.2;
//編譯器自動(dòng)推演,隱式實(shí)例化
cout << Add(a, b) << endl;
cout << Add(c, d) << endl;
//推演實(shí)例化矛盾,編譯器無(wú)法確定此處到底該將T確定為int或者double類(lèi)型而報(bào)錯(cuò)
//cout << Add(a, d) << endl;
//倆種處理方式:1、強(qiáng)制轉(zhuǎn)換類(lèi)型 2、顯示實(shí)例化
//1.強(qiáng)制轉(zhuǎn)換類(lèi)型
cout << Add((double)a, d) << endl;
cout << Add(a, (int)d) << endl;
//2.顯示實(shí)例化
cout << Add<double>(a, d) << endl;
cout << Add<int>(a, d) << endl;
return 0;
}
3.3 模板參數(shù)的匹配原則
1.一個(gè)非模板函數(shù)可以和一個(gè)同名的函數(shù)模板同時(shí)存在,而且該函數(shù)模板還可以被實(shí)例化為這個(gè)非模板函數(shù)。
2.對(duì)于非模板函數(shù)和同名函數(shù)模板,如果其他條件都相同,在調(diào)動(dòng)時(shí)會(huì)優(yōu)先調(diào)用非模板函數(shù)而不會(huì)從該模板產(chǎn)生出一個(gè)實(shí)例。如果模板可以產(chǎn)生一個(gè)具有更好匹配的函數(shù), 那么將選擇模板。
3.模板函數(shù)不允許自動(dòng)類(lèi)型轉(zhuǎn)換,但普通函數(shù)可以進(jìn)行自動(dòng)類(lèi)型轉(zhuǎn)換。
//專(zhuān)門(mén)處理加法的函數(shù)
int Add(const int& x, const int& y)
{
return x + y;
}
//通用加法函數(shù)
template<class T>
T Add(const T& x, const T& y)
{
return x + y;
}
template<class T1, class T2>
T2 Add(const T1& x, const T2& y)
{
return x + y;
}
int main()
{
cout << Add(1, 2) << endl;//調(diào)用int Add函數(shù)
cout << Add(1.1, 2.2) << endl;//調(diào)用T Add函數(shù)
cout << Add(1, 2.2) << endl;//調(diào)用T2 Add函數(shù)
return 0;
}
4. 類(lèi)模板
格式:
template<class T1, class T2, …, class Tn>
class 類(lèi)模板名
{
// 類(lèi)內(nèi)成員定義
};
template<class T>
class Stack
{
public:
Stack(size_t capacity = 4)
:_a(nullptr)
,_top(0)
,_capacity(0)
{
if (capacity > 0)
{
_a = new T[capacity];
_capacity = capacity;
_top = 0;
}
}
~Stack()
{
delete[] _a;
_a = nullptr;
_top = _capacity = 0;
}
void Push(const T& x)
{}
//注意:類(lèi)模板中函數(shù)放在類(lèi)外進(jìn)行定義時(shí),需要加模板參數(shù)列表
private:
T* _a;
size_t _top;
size_t _capacity;
};
注意:類(lèi)模板中函數(shù)放在類(lèi)外進(jìn)行定義時(shí),需要加模板參數(shù)列表
4.1 類(lèi)模板的實(shí)例化
類(lèi)模板實(shí)例化與函數(shù)模板實(shí)例化不同,類(lèi)模板實(shí)例化需要在類(lèi)模板名字后跟<>,然后將實(shí)例化的類(lèi)型放在<>中即可,類(lèi)模板名字不是真正的類(lèi),而實(shí)例化的結(jié)果才是真正的類(lèi)。
template<class T>
class Stack//這里Stack不是具體的類(lèi),是編譯器根據(jù)被實(shí)例化的類(lèi)型生成具體類(lèi)的模具
{
public:
Stack(size_t capacity = 4)
:_a(nullptr)
,_top(0)
,_capacity(0)
{
if (capacity > 0)
{
_a = new T[capacity];
_capacity = capacity;
_top = 0;
}
}
~Stack()
{
delete[] _a;
_a = nullptr;
_top = _capacity = 0;
}
void Push(const T& x)
{}
private:
T* _a;
size_t _top;
size_t _capacity;
};
int main()
{
//類(lèi)模板都是顯示實(shí)例化
//雖然他們用了一個(gè)類(lèi)模板,但是Stack<int>,Stack<char>是兩個(gè)類(lèi)型
Stack<int> st1;
Stack<char> st2;
//知道要存多少個(gè)數(shù)據(jù),避免插入時(shí)擴(kuò)容消耗
Stack<int> st3(100);
return 0;
}
注意:
1.類(lèi)模板必須顯示實(shí)例化。
2.雖然上面兩個(gè)對(duì)象用了同一個(gè)類(lèi)模板,但是Stack<int>,Stack<char>是兩個(gè)不同的類(lèi)型。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-453830.html
5. 結(jié)尾
C++模板入門(mén)的相關(guān)知識(shí)點(diǎn)我們就學(xué)習(xí)完了,學(xué)了模板以后,在很多地方我們就可以用模板來(lái)實(shí)現(xiàn),而不是重載函數(shù),這能極大的提高效率和可維護(hù)性。
最后,感謝各位大佬的耐心閱讀和支持,覺(jué)得本篇文章寫(xiě)的不錯(cuò)的朋友可以三連關(guān)注支持一波,如果有什么問(wèn)題或者本文有錯(cuò)誤的地方大家可以私信我,也可以在評(píng)論區(qū)留言討論,再次感謝各位。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-453830.html
到了這里,關(guān)于【C++】——模板(泛型編程+函數(shù)模板+類(lèi)模板)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!