C++模板
1 模板的概念
模板 字面意思和模型相似,造一個東西,總會有一個模型爲基礎。如果以後有什麼改動,也要在模型的基礎上改在。 這麼想,大家都知道了 c++裏模板也一樣也是模型,那這個模型有什麼用呢 。
例如,我們希望編寫一個函數來比較倆個值,並指出第一個值,是小於?還是大於?還是等於,第二個值。在以前,我們可能想要定義多個函數,每個函數比較一種特定的類型的值。我們會寫個重載函數:
int compare(const string &v1,const string &v2)
{
if(v1<v2)
return 1;
if(v2<v1)
return -1;
return 0;
}
int compare(const double&v1,const double &v2)
{
if(v1<v2)
return 1;
if(v2<v1)
return -1;
return 0;
}
這兩個函數幾乎相同,唯一的差異就是參數類型不同,函數體則完全相同。
如果對每種希望比較的類型都不得不重複定義完全一樣的函數體,是非常容易出錯的 。甚至讓人崩潰(在我以前不知道模板的時候)
但是模板出現後,就大大不一樣了,很方便,用法也很簡單。接下來學習簡單的函數模板。
1.1 函數模板
我們可以定義一個通用的函數模板,而不是爲每個類型定義一個新函數。一個函數模板就是一個模型一個公式,可以生成特定類型的函數版本。compare模板可以像這樣定義。
template <typename T>
int compare (const T &v1 , const T &v2)
{
if(v1<v2)return 1;
if(v2<v1)return -1;
return 0;
}
1.1.1 函數模板的格式:
template <class 形參名,class 形參名,......> 返回類型 函數名(參數列表)
{
函數體
}
其中template和class,沒錯,他兩是一樣的。在這裏typename 和class沒區別
以關鍵字 template開始,後面跟一個模板參數列表。用< >包圍起來。
1.1.2 實例化函數模板
當我們調用一個函數模板時候,編譯器 用 函數的實參 來爲我們推斷 模板的實參類型。比如,我們調用上面的compar時候,編譯器就知道自己的模板參數T是什麼類型了。
cout << compare(1,0)<<endl; //T爲 int類型
實參類型是 int 編譯器會推斷出模板實參 爲 int ,並將它綁定到模板參數 T 上。
接着,編譯器根據 他自己推斷出的 模板參數 來爲我們 實例化一個特定的函數,(就專門爲你制定的哦)。
當編譯器實例化一個模板時,她會使用實際的模板參數 代替 對應的模板參數 來創建出模板的一個新實例。
例如 :
//實例化出 int comnpare (const int &, const int &)
cout <<compare (1 , 0) << endl; //T 爲 int
//實例化出 int compare(const vector<int>&,const //vector<int>&
vector<int> vec{1,2,3},vwc2{4,5,6};
cout <<compare(vec1,vec2)<<endl; // T爲 vector<int>
編譯器會實例化兩個不同的 compare。
1.2 類模板
類模板 是用來生成類的藍圖的,與函數模板不同的地方是,編譯器不能爲類模板推斷模板參數類型。 除非有額外的信息,接下來會說到。
定義類模板
1.2.1、類模板的格式爲:
template<class 形參名,class 形參名,…> class 類名
{ ... };
類似函數模板,類模板以關鍵字 template 開始,後面跟模板參數列表。在類模板及其中的成員,我們將模板參數當做替身,代替使用模板的時候,用戶需要提供類型 或 值。
以下是一些例子 大家參考一下。
// ClassTemplate.h
template<typename T1,typename T2>
class myClass{
private:
T1 I;
T2 J;
public:
myClass(T1 a, T2 b);//Constructor
void show();
};
//這是構造函數
//注意這些格式
template <typename T1,typename T2>
myClass<T1,T2>::myClass(T1 a,T2 b):I(a),J(b){}
//這是void show();
template <typename T1,typename T2>
void myClass<T1,T2>::show()
{
cout<<"I="<<I<<", J="<<J<<endl;
}
// Test.cpp
#include<iostream>
#include"ClassTemplate.h"
using std::cout;
using std::endl;
void main()
{
myClass<int,int> class1(3,5);
class1.show();
myClass<int,char> class2(3,"a");
class2.show();
myClass<double,int> class3(2.9,10);
class3.show();
system("PAUSE");
}
1.2.1 類模板和函數模板,都是以template開始,後接模板形參列表組成。模板形參不能爲空,一但聲明瞭類模板就可以用類模板的形參名,聲明類中的成員變量和成員函數。即可以在類中使用內置類型的地方都可以使用模板形參名來聲明。比如
template<class T>
class A {
public:
T a; T b;
T hy(T c, T &d);
};
//在類A中聲明瞭兩個類型爲T的成員變量a和b,還聲明瞭一個返回類型爲T帶兩個參數類型爲T的函數hy。
1.2.3
類模板對象的創建:比如一個模板類A,則使用類模板創建對象的方法爲A< i n t > m;在類A後面跟上一個<>尖括號並在裏面填上相應的類型,這樣的話類A中凡是用到模板形參的地方都會被int 所代替。當類模板有兩個模板形參時創建對象的方法爲A < int, double > m;類型之間用逗號隔開。
1.2.4
對於類模板,模板形參的類型必須在類名後的尖括號中明確指定。比如A< 2 > m;用這種方法把模板形參設置爲int是錯誤的(編譯錯誤:error C2079: ‘a’ uses undefined class ‘A< int >’),類模板形參不存在實參推演的問題。也就是說不能把整型值2推演爲int 型傳遞給模板形參。要把類模板形參調置爲int 型必須這樣指定A< int > m。
1.2.5
在類模板外部定義成員函數的方法爲:
template<模板形參列表> 函數返回類型 類名<模板形參名>::函數名(參數列表){函數體},
比如有兩個模板形參T1,T2的類A中含有一個void h()函數,則定義該函數的語法爲:
template<class T1,class T2> void A<T1,T2>::h(){}
注意:當在類外面定義類的成員時template後面的模板形參應與要定義的類的模板形參一致。
1.2.6
再次提醒注意:模板的聲明或定義只能在全局,命名空間或類範圍內進行。即不能在局部範圍,函數內進行,比如不能在main函數中聲明或定義一個模板。