1.模板的概念:
模板是實現類屬機制的一種工具,它的功能非常強,它是無約束類屬機制和約束類屬機制的集合。 它可以讓用戶構造模板函數。
模板,對象, 函數之間的關係見下圖:
2.函數模板與模板函數:
先見下例:
#include <iostream.h>
template<class T> //模板聲明
T max(T x,T y) //定義模板
{
return (x>y)? x:y;
}
main()
{
int i=10,j=56;
float x1=50.34, x2=56.34;
double y1=673.36, y2=465.972;
cout<<"the max of i, j is:"<<max(i, j)<<"/n";
cout<<"the max of x1, x2 is:" <<max(x1,x2)<<"/n";
cout<<"the max of y1, y2 is:" <<max(y1,y2)<<"/n";
return 1;
}
上面的這個程序雖然只是實現一個很簡單的比較大小的問題, 但如果不用模板, 而用我們以前的方法, 由於參數類型和返回值類型不同將需要三個函數來實現, 這樣是十分麻煩的。模板成功的解決了這個問題, 程序中生成了三個模板函數, 其中max(i,j)用模板實參int將類型實參數T進行了實例化;max(x1,x1)用模板實參float將類型參數T進行了實例化;max(y1,y2)用模板實參double將類型參數T進行了實例化。
從上面的例子我們可以看出, 函數模板提供了一類函數的抽象, 它以任意類型T爲參數及函數返回值。由一個函數模板產生的函數稱爲模板函數, 它是函數模板的具體實例。
函數模板和模板函數的關係圖:
要提醒大家注意的一點是:雖然模板參數T可以實例化成各種類型, 但是採用模板參數T的各種參數T的各參數之間必須保持完全一致的類型。例如:
T max(T x,T y)
{
return (x>y)?x:y;
}
void func(int i, char c, float f)
{
max(i,i); //正確
max(c,c); //正確
max(c,i); //錯誤
max(f,i); //錯誤
}
解決上面的問題就需要引入一個型的概念—重載, 既可以用非模板函數重載一個同名的函數模板。 重載有兩種表述方式:
1.利用函數模板的函數體
使用次方法是必須注意各模板參數的實參類型必須一致。例如:
int max(int,int)
2.重新定義函數體
對於要重新定義函數體的重載函數, 所帶參數的類型可以隨意, 就象一般的重載函數一樣定義。
定義重載函數特別要注意避免產生預期的和非預期的二義性。例如:
int max(int, int);
char max(int x,char y)
{
//......
}
當進行函數調用時有這樣一個調用形式:
msx(i,f);
此處i爲int,f爲float,這個函數調用就存在着二義性。這時的調用就需要按照一定的規則安排先後順序, 這些規則就是函數模板與同名的非模板函數的重載方法均遵循的約定:
(1)尋找一個參數完全匹配的函數, 如果找到了就調用它。
(2)在(1)失敗後, 尋找一個函數模板, 使其實例化, 產生一個匹配的模板函數, 若找到了,就調用它。
(3)在(1)(2)均失敗後, 再試一試低一級的對函數的重載方法,例如通過類型轉換可產生參數匹配等, 若找到了,就調用它。
(4)若(1)(2)(3)均失敗, 則這是一個錯誤的調用。
學習注:函數重載可以對參數進行隱式轉化,但一旦加入了template,參數類型不匹配就會產生問題,如定義float max(float x,float y)
{
cout<<"don't use template"<<endl;
return (x>y)?x:y;
}
如果沒有template,則調用max(float ,int)不會有問題,編譯器會對int 進行轉化,如果加入了template,則會出現錯誤。說明template對參數類型的要求更嚴格。
3.類模板與模板類
類模板與模板類的概念
一個類模板可以讓用戶爲類定義一種模式, 使得類中的某些數據成員,某些成員函數的參數,某些成員函數的返回值,能取任意類型。
定義一個類模板, 一般由兩方面的內容:
(1)首先要定義類, 其格式爲:
template<class T> //聲明一個模板
class name
{
//....
}
name爲類名,在類定義體中如採用數據類型的成員, 函數參數的前面需加上T。例如:
template<class T>
class vector
{
T * data;
int size;
pulic:
vetor(int);
T&operator[](int);
//...
};
(2)在類定義體外定義成員函數時, 若此成員函數中有模板參數存在, 則需在函數體外進行模板聲明, 並且在函數名前的類名後綴上“<T>”.例如:
template<class T>
vector<T>::vector(int i)
{
//....
}
template<class T>
T&vector<T>::operator[](int i)
{
//....
}
類模板的使用
類模板的使用實際上是將類模板實例化成一個具體的類, 它的格式爲:
類名<實際的類型>
例如:
main()
{
vector<int>x(5);
for(int i=0; i<=5;i++)
x[i]=i;
for(i=0;i<5;++i)
cout<<x[i]<<"";
cout<<"/n";
}
類模板和模板類之間的關係, 如圖:
類模板使用需要注意的幾點:
(1)在每個模板定義之前, 不管是類模板還是函數模板, 都需要在前面加上模板聲明:
template<class T>
(2)類模板和結構模板在使用時, 必須在名字後面綴上模板參數<T>,如:list<T>,node<T>.
學習注:計算機是懶人的好朋友,template的產生,可以減少代碼量,增加代碼的複用。c++是由類和函數構成的。template也可以自動生成相應的類和對象。關於使用template的具體語法,也要注意。注意:template對參數類型的要求很嚴格,不支持隱式的參數類型轉化。對於參數類型不同的使用場合,可以使用函數重載。