?????作者: @情話0.0
??專欄:《C++從入門到放棄》
??個(gè)人簡(jiǎn)介:一名雙非編程菜鳥,在這里分享自己的編程學(xué)習(xí)筆記,歡迎大家的指正與點(diǎn)贊,謝謝!
一、泛型編程是什么?
??以我們之前所學(xué)的知識(shí),假如要實(shí)現(xiàn)一個(gè)通用的加法函數(shù),那么可以通過(guò)函數(shù)重載的方式來(lái)實(shí)現(xiàn)。
void Add(const int& a,const int& b)
{
return a+b;
}
void Add(const double& a,const double& b)
{
return a+b;
}
void Add(const char& a,const char& b)
{
return a+b;
}
使用函數(shù)重載雖然可以實(shí)現(xiàn),但是有以下幾個(gè)不好的地方:
- 重載的函數(shù)僅僅只是參數(shù)類型不同,代碼的復(fù)用率比較低,一旦有新類型的參數(shù)出現(xiàn)時(shí),就需要增加對(duì)應(yīng)的函數(shù);
- 代碼的可維護(hù)性比較低,一個(gè)出錯(cuò)可能所有的重載均出錯(cuò)。
??為了解決上面因?yàn)楹瘮?shù)重載而出現(xiàn)的幾個(gè)問(wèn)題,便有了泛型編程,那什么是泛型編程呢?
泛型編程:編寫與類型無(wú)關(guān)的通用代碼,是代碼復(fù)用的一種手段。模板是泛型編程的基礎(chǔ),而這個(gè)模板就類似于一個(gè)澆筑模具,通過(guò)給這個(gè)模具中填充不同的材料(參數(shù)類型)來(lái)獲得不同材質(zhì)的鑄件(生成的具體類型代碼)。
- 模板是C++支持參數(shù)化多態(tài)的工具,使用模板可以使用戶為類或者函數(shù)聲明一種一般模式,使得類中的某些數(shù)據(jù)成員或者成員函數(shù)的參數(shù)、返回值取得任意類型;
- 模板是一種對(duì)類型進(jìn)行參數(shù)化的工具;
- 通常有兩種形式:函數(shù)模板和類模板;
- 函數(shù)模板僅針對(duì)參數(shù)類型不同的函數(shù);
- 類模板僅針對(duì)數(shù)據(jù)成員和成員函數(shù)類型不同的類;
- 使用模板的目的就是能夠讓程序員編寫與類型無(wú)關(guān)的代碼。比如編寫了一個(gè)求和兩個(gè)整型int 類型的Add函數(shù),這個(gè)函數(shù)就只能實(shí)現(xiàn)int 型,對(duì)double,字符這些類型無(wú)法實(shí)現(xiàn),要實(shí)現(xiàn)這些類型的交換就要重新編寫另一個(gè)Add函數(shù)。使用模板的目的就是要讓這程序的實(shí)現(xiàn)與類型無(wú)關(guān),比如一個(gè)Add模板函數(shù),即可以實(shí)現(xiàn)int 型,又可以實(shí)現(xiàn)double型的求和
二、函數(shù)模板
1. 什么是函數(shù)模板?
??函數(shù)模板代表了一個(gè)函數(shù)聚合體,該函數(shù)模板與參數(shù)類型無(wú)關(guān),在函數(shù)調(diào)用的時(shí)候根據(jù)傳參的類型將函數(shù)模板里的參數(shù)進(jìn)行參數(shù)化,也就是根據(jù)實(shí)參類型產(chǎn)生函數(shù)的特定類型版本。
2. 函數(shù)模板的格式
template<typename T1, typename T2,…,typename Tn>
返回值類型 函數(shù)名(參數(shù)列表){}
示例:
template <typename T> // 模板參數(shù)列表:聲明類型
T Add(const T& a,const T& b)
{
return a+b;
}
注意:typename是用來(lái)定義模板參數(shù)關(guān)鍵字,也可以使用class,但是不能使用struct代替class
3. 函數(shù)模板的原理
??函數(shù)模板是一個(gè)藍(lán)圖,它本身并不是函數(shù),是編譯器用使用方式產(chǎn)生特定具體類型函數(shù)的模具。所以其實(shí)模板就是將本來(lái)應(yīng)該我們做的重復(fù)的事情交給了編譯器。
??在這里,我舉一個(gè)例子,我們上面所列舉的這個(gè)函數(shù)模板就是相當(dāng)于一個(gè)制作螺絲的模具,它本身不是螺絲,需要用這個(gè)模具在壓鑄出來(lái)螺絲,這個(gè)螺絲才相當(dāng)于真正的函數(shù),使用螺絲也就相當(dāng)于調(diào)用函數(shù)。
??在編譯器編譯階段,對(duì)于模板函數(shù)的使用,編譯器需要根據(jù)傳入的實(shí)參類型來(lái)推演生成對(duì)應(yīng)類型的函數(shù)以供調(diào)用。
4. 函數(shù)模板實(shí)例化
??用不同類型的參數(shù)使用函數(shù)模板時(shí),稱為函數(shù)模板的實(shí)例化。模板參數(shù)實(shí)例化分為:隱式實(shí)例化和顯式實(shí)例化。
4.1 隱式實(shí)例化
??讓編譯器根據(jù)實(shí)參推演模板參數(shù)的實(shí)際類型
template<class T>
T Add(const T& left, const T& right)
{
return left + right;
}
int main()
{
int a1 = 10, a2 = 20;
double d1 = 10.0, d2 = 20.0;
Add(a1, a2);
Add(d1, d2);
Add(a1,d2); //錯(cuò)誤
Add(a1,(int)d1);
return 0;
}
??解釋一下為什么第三條 Add 語(yǔ)句不能通過(guò)編譯,因?yàn)樵诰幾g期間,當(dāng)編譯器看到該實(shí)例化時(shí),需要推演出其實(shí)參類型,通過(guò)實(shí)參 a1 將 T 推演為 int,通過(guò)實(shí)參 d1 將 T 推演為 double 類型,但模板參數(shù)列表中只有一個(gè) T,編譯器無(wú)法確定此處到底該將 T 確定為 int 或者 double 類型而報(bào)錯(cuò)。注意:在模板中,編譯器一般不會(huì)進(jìn)行類型轉(zhuǎn)換操作,因?yàn)橐坏┺D(zhuǎn)化出問(wèn)題,那就是編譯器的鍋。
??而對(duì)于上述的問(wèn)題可以有兩種處理方式:用戶自己強(qiáng)制轉(zhuǎn)化(第四條Add語(yǔ)句);使用顯示實(shí)例化
4.2 顯式實(shí)例化
??在函數(shù)名后的<>中指定模板參數(shù)的的實(shí)際類型
int main()
{
int a = 10;
double b = 10.0;
double c = 20.0;
Add<int>(a, b);
Add<int>(b, c);
return 0;
}
如果類型不匹配,編譯器會(huì)嘗試進(jìn)行隱式類型轉(zhuǎn)換,如果無(wú)法轉(zhuǎn)換成功編譯器將會(huì)報(bào)錯(cuò)。
5. 模板參數(shù)匹配原則
- 一個(gè)非模板函數(shù)和一個(gè)同名的函數(shù)模板同時(shí)存在,而且該函數(shù)模板還可以被實(shí)例化為這個(gè)非模板函數(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;
}
void Test()
{
Add(1, 2); // 與非模板函數(shù)匹配,編譯器不需要特化
Add<int>(1, 2); // 調(diào)用編譯器特化的Add版本
Add(1,2.0); //調(diào)用非模板函數(shù),但是可能會(huì)導(dǎo)致數(shù)據(jù)丟失
}
- 對(duì)于非模板函數(shù)和同名函數(shù)模板,如果其他條件都相同,在調(diào)動(dòng)時(shí)會(huì)優(yōu)先調(diào)用非模板函數(shù)而不會(huì)從該模板產(chǎn)生出一個(gè)實(shí)例。如果模板可以產(chǎn)生一個(gè)具有更好匹配的函數(shù)(不需要參數(shù)類型的轉(zhuǎn)換), 那么將選擇模板。
// 專門處理int的加法函數(shù)
int Add(int left, int right)
{
return left + right;
}
// 通用加法函數(shù)
template<class T1,class T2>
T Add(T1 left, T2 right)
{
return left + right;
}
void Test()
{
Add(1, 2); // 與非模板函數(shù)匹配,編譯器不需要特化
Add(1, 2.0); // 模板函數(shù)可以生成更加匹配的版本,編譯器根據(jù)實(shí)參生成更加匹配的Add函數(shù)
}
- 模板函數(shù)不允許自動(dòng)類型轉(zhuǎn)換,但普通函數(shù)可以進(jìn)行自動(dòng)類型轉(zhuǎn)換
二、類模板
3.1 類模板的定義格式
template<class T1, class T2, ..., class Tn>
class 類模板名
{
// 類內(nèi)成員定義
};
// 動(dòng)態(tài)順序表
// 注意:Vector不是具體的類,是編譯器根據(jù)被實(shí)例化的類型生成具體類的模具
template<class T>
class Vector
{
public :
Vector(size_t capacity = 10)
: _pData(new T[capacity])
, _size(0)
, _capacity(capacity)
{}
// 使用析構(gòu)函數(shù)演示:在類中聲明,在類外定義。
~Vector();
void PushBack(const T& data);
void PopBack();
// ...
size_t Size() {return _size;}
T& operator[](size_t pos)
{
assert(pos < _size);
return _pData[pos];
}
private:
T* _pData;
size_t _size;
size_t _capacity;
};
// 注意:類模板中函數(shù)放在類外進(jìn)行定義時(shí),需要加模板參數(shù)列表
template <class T>
Vector<T>::~Vector()
{
if(_pData)
delete[] _pData;
_size = _capacity = 0;
}
3.2 類模板實(shí)例化
類模板實(shí)例化與函數(shù)模板實(shí)例化不同,類模板實(shí)例化需要在類模板名字后跟<>,然后將實(shí)例化的類型放在<>中即可,類模板名字不是真正的類,而實(shí)例化的結(jié)果才是真正的類。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-413502.html
// Vector類名,Vector<int>才是類型
Vector<int> s1;
Vector<double> s2;
總結(jié)
以上就是我自己對(duì)于學(xué)習(xí)模板的總結(jié),希望各位看官遇到不足之處幫我指正出來(lái),咱們一塊互相學(xué)習(xí),討論,也希望我的略解能夠幫助到你。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-413502.html
到了這里,關(guān)于【C++從入門到放棄】模板介紹(函數(shù)模板、類模板)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!