1.泛型的基本思想
泛型編程(Generic Programming)是一種語言機制,通過它可以實現一個標准的容器庫。像類一樣,泛型也是一種抽象數據類型,但是泛型不屬於面向對象,它是面向對象的補充和發展。
在面向對象編程中,當算法與數據類型有關時,面向對象在對算法的抽象描述方面存在一些缺陷。
比如對棧的描述:
class stack
{
push(參數類型) //入棧算法
pop(參數類型) //出棧算法
}
如果把上面的偽代碼看作算法描述,沒問題,因為算法與參數類型無關。但是如果把它寫成可編譯的源代碼,就必須指明是什么類型,否則是無法通過編譯的。使用重載來解決這個問題,即對N種不同的參數類型寫N個push和pop算法,這樣是很麻煩的,代碼也無法通用。
若對上面的描述進行改造如下:
首先指定一種通用類型T,不具體指明是哪一種類型。
class stack<參數模板 T>
{
push(T) //入棧算法
pop(T) //出棧算法
}
這里的參數模板T相當於一個占位符,當我們實例化類stack時,T會被具體的數據類型替換掉。
若定義對象S為statc類型,在實例化S時若我們將T指定int型則:
這時候類S就成為:
class S
{
push(int) //入棧算法
pop(int) //出棧算法
}
這時我可以稱class stack<參數模板 T>是類的類,通過它可以生成具體參數類型不同的類。
2.泛型在C++中的應用
泛型在C++中的主要實現為模板函數和模板類。
通常使用普通的函數實現一個與數據類型有關的算法是很繁瑣的,比如兩個數的加法,要考慮很多類型:
int add(int a,int b) { return a+b; }
float add(float a,float b) { return a+b; }
。。。。
雖然在C++中可以通過函數重載來解決這個問題,但是反復寫相同算法的函數是比較辛苦的,更重要的是函數重載是靜態編譯,運行時占用過多內存。
在此我們可以用C++的模板函數來表達通用型的函數,如下:
template<typename T> // 模板聲明
T add(T a,T b) { return a+b; } // 注意形參和返回值的類型
這時C++編譯器會根據add函數的參數類型來生成一個與之對應的帶具體參數類型的函數並調用。
例如:
#include <iostream>
using namespace std;
template <typename T>
T add(T a,T b) //注意形參和返回類型
{
return a+b;
}
void main()
{
int num1, num2, sum;
cin>>num1>>num2;
sum=add(num1,num2); //用int匹配模版參數T,若sum,num1,num2類型不一致則無法匹配。
cout<<sum;
}
3.函數模板的性質
1) 函數模板並不是真正的函數,它只是C++編譯生成具體函數的一個模子。
2) 函數模板本身並不生成函數,實際生成的函數是替換函數模板的那個函數,比如上例中的add(sum1,sum2),
這種替換是編譯期就綁定的。
3) 函數模板不是只編譯一份滿足多重需要,而是為每一種替換它的函數編譯一份。
4) 函數模板不允許自動類型轉換。
5) 函數模板不可以設置默認模板實參。比如template <typename T=0>不可以。
4.C++模版函數的語法
template <typename 模版參數列表…>
函數返回類型 函數名(形參列表…)
上面兩行可以合並成一行。
例如:
下面的幾種寫法是等效的並且class 和typename是可以互換的。
template <typename T1, typename T2>
T1 fun(T1, T2, int )
{ //…..}
template <typename T1,T2> T1 fun(T1, T2, int )
{ //…..}
template <class T1, class T2>
T1 fun(T1, T2, int )
{ //…..}
template <class T1,T2> T1 fun(T1, T2, int )
{ //…..}
5.C++模版類的語法
template <class 模版參數列表…>
class 類名
{ //類體}
成員的實現…
例如:
//類聲明部分,有兩個模板參數T1,T2
template <class T1, class T2 >
class A {
private:
int a;
T1 b; //成員變量也可以用模板參數
public:
int fun1(T1 x, int y );
T2 fun2(T1 x, T2 y);
}
//類實現部分
template <class T1, class T2 >
int A<T1>:: fun1(T1 x, int y ){//實現…… }
template <class T1, class T2 >
T2 A<T1,T2>:: fun2(T1 x, T2 y) {//實現…… }
//使用類A
int main( ) {
//定義對象a,並用int替換T1, float替換T2
A<int, float> a;
//實例化a,調用a的屬性和方法……
}
由上例可以看出, 類模板參數T1,T2對類的成員變量和成員函數均有效。
在C++編程中,當你要實現的一個類的某些成員函數和成員變量的算法跟數據類型有關,可以考慮用類模板,且C++版的數據結構算法大都用類模板實現。
6.類模板的性質
1) 類模板不是真正的類,它只是C++編譯器生成具體類的一個模子。
2) 類模板可以設置默認模板實參。