模板
我們知道,如果要用一個交換函數,那麼要交換int型的兩個數,就需要寫一個int類型的交換函數,如果交換char類型的兩個字符,就需要寫一個char類型的交換函數。這樣會造成代碼的複用率低,雖然函數重載可以實現,但是函數的複用率仍然很低,且如果一個出錯,那可能所有重載都會出錯,爲了解決這一問題,C++中引入了模板這一概念。
首先需要了解一下泛型編程的概念:
編寫與類型無關的通用代碼,是代碼複用的一種手段。模板是泛型編程的基礎。
函數模板
函數模板:
函數模板代表了一個函數家族,該函數模板與類型無關,在使用時被參數化,根據實參類型產生函數的特定 類型版本。
函數模板格式:
template<typename/class T1, typename/class T2,…,typename/class Tn>
比如交換函數我們可以寫成
隱式實例化:編譯器自己會去匹配類型
template<class type>
void swap(type& left,type& right)
{
type tmp = left;
left = right;
right = tmp;
}
這樣,每次調用swap函數時,編譯器會根據參數類型,自動確定類型,並進行交換。
注意:
函數模板是一個藍圖,它本身並不是函數,是編譯器用使用方式產生特定具體類型函數的模具。所以其實模 板就是將本來應該我們做的重複的事情交給了編譯器
在編譯器編譯階段,對於模板函數的使用,編譯器需要根據傳入的實參類型來推演生成對應類型的函數以供 調用。比如:當用double類型使用函數模板時,編譯器通過對實參類型的推演,將T確定爲double類型,然 後產生一份專門處理double類型的代碼,對於字符類型也是如此。
但是下面這樣使用是不對的:
template<class type>
void swap(type& left,type& right)
{
type tmp = left;
left = right;
right = tmp;
}
int main()
{
int a = 10;
char b = 'a';
swap(a,b);
}
因爲編譯器無法斷定到底是int類型還是char類型
因此模板函數需要寫成這樣
template<class type,class> type2>
void swap(type& left,type2& right)
{
type tmp = left;
left = right;
right = tmp;
}
顯示實例化:在函數名後的<>中指定模板參數的實際類型
template<class T>
T add(T& a,T& b)
{
return a + b;
}
void test()
{
int a = 10;
double b = 20.5;
add<int>(a,b);//顯式實例化成int類型
}
模板函數匹配原則
1.普通函數與模板函數共存時,如果普通函數的參數類型可以完全匹配,則執行普通函數,不進行模板函數的實例化。
2.普通函數與模板函數共存時,普通函數的參數類型不能完全匹配,但是實例化的函數可以完全匹配參數類型,則進行實例化。
3.普通函數與模板函數共存時,但是指定了需要實例化,則進行實例化。
類模板
格式如下:
template<class T1, class T2, ..., class Tn>
class 類模板名
{
// 類內成員定義
};
例如:
template<class T1,class T2,class T3>
class date
{
public:
date(T1 year,T2 month,T3 day)
:_year(year)
,_month(month)
,_day(day)
{}
private:
T1 _year;
T2 _month;
T3 _day;
};
如果在類外定義類模板的成員函數,則需要加上泛性申明以及作用域(類名+<泛性參數>)。
template<class T1,class T2,classT3>
void date<T1,T2,T3>::display()
{
cout<<_year<<" "<<_month<<' '<<_day<<endl;
}
注意:類模板實例化與函數模板實例化不同,類模板實例化需要在類模板名字後跟<>,然後將實例化的類型放在<> 中即可,類模板名字不是真正的類,而實例化的結果纔是真正的類。