6.3 類模板和模板類
所謂類模板,實際上是建立一個通用類,其數據成員、成員函數的返回值類型和形參類型不具體指定,用一個虛擬的類型來代表。使用類模板定義對象時,系統會實參的類型來取代類模板中虛擬類型從而實現了不同類的功能。
定義一個類模板與定義函數模板的格式類似,必須以關鍵字template開始,后面是尖括號括起來的模板參數,然后是類名,其格式如下:
template <typename 類型參數>
class 類名{
類成員聲明
};
或者
template <class 類型參數>
class 類名{
類成員聲明
};
(1)template:是一個聲明模板的關鍵字,它表明聲明一個模板
(2)類型參數:通常用C++標識符表示,如T、Type等,實際上是一個虛擬的類型名,現在未指定它是哪一種具體的類型,但使用類模板時,必須將類型參數實例化。
(3)typename和class的作用相同,都是表示其后面的參數是一個虛擬的類名(即類型參數).
在類聲明中,欲采用通用數據類型的數據成員、成員函數的參數或返回類型前面需要加上類型參數。
如建立一個用來實現求兩個數最大值的類模板
template<typename T> //模板聲明,其中T為類型參數 class Compare{ public: Compare(T i,T j) { x = i; y = j; } T max() { return (x>y)?x:y; } private: T x,y; };
用類模板定義對象時,采用以下形式:
類模板名<實際類型名>對象名[(實參表列)];
因此,使用上面求最大值的類型模板的主函數可寫成:
int main() { Compare<int>com1(3,7); Compare<double>com2(12.34,56.78); Compare<char>com3('a','x'); cout<<"其中的最大值是:"<<com1.max()<<endl; cout<<"其中的最大值是:"<<com2.max()<<endl; cout<<"其中的最大值是:"<<com3.max()<<endl; return 0; }
//例6.6 類模板compare的使用舉例
#include<iostream.h> template<typename T> //模板聲明,其中T為類型參數 class Compare{ public: Compare(T i,T j) { x = i; y = j; } T max() { return (x>y)?x:y; } private: T x,y; }; int main() { Compare<int>com1(3,7); //用類模板定義對象com1,此時T被int替代 Compare<double>com2(12.34,56.78); //用類模板定義對象com2,此時T被double替代 Compare<char>com3('a','x'); //用類模板定義對象com3,此時T被char替代 cout<<"其中的最大值是:"<<com1.max()<<endl; cout<<"其中的最大值是:"<<com2.max()<<endl; cout<<"其中的最大值是:"<<com3.max()<<endl; return 0; } /* 程序運行結果是: 其中的最大值是:7 其中的最大值是:56.78 其中的最大值是:x */
在以上例子中,成員函數(其中含有類型參數)是定義類體內的。但是,類模板中的成員函數,也可以在類模板外定義。此時,若成員函數中有參數類型存在,則C++有一些特殊的規定:
(1)需要在成員函數定義之前進行模板聲明;
(2)在成員函數名前綴上"類名<類型參數>::";
在類模板外定義成員函數的一般形式如下:
temlate<typename 類型參數> 函數類型 類名<類型參數>::成員函數名(形參表) { 函數體; } 如上題中成員函數max在類模板外定義時,應該寫成: template<typename T> T Compare<T>::max() { return (x>y)?x:y; }
//例6.7 在類模板外定義成員函數函數舉例。
#include<iostream.h> template<typename T> //模板聲明,其中T為類型參數 class Compare{ public: Compare(T i,T j) { x = i; y = j; } T max(); private: T x,y; }; template<class T> T Compare<T>::max() { return (x>y)?x:y; } int main() { Compare<int>com1(3,7); //用類模板定義對象com1,此時T被int替代 Compare<double>com2(12.34,56.78); //用類模板定義對象com2,此時T被double替代 Compare<char>com3('a','x'); //用類模板定義對象com3,此時T被char替代 cout<<"其中的最大值是:"<<com1.max()<<endl; cout<<"其中的最大值是:"<<com2.max()<<endl; cout<<"其中的最大值是:"<<com3.max()<<endl; return 0; } /* 程序運行結果是: 其中的最大值是:7 其中的最大值是:56.78 其中的最大值是:x 此例中,類模板Compare經實例化后生成了3個類型分別為int、double、char的模板類,這3個模板類 經實例化后又生成了3個對象com1、com2、com3。類模板代表了一類類,模板類表示某一具體的類。關系如下: 類模板 Compare<T> 實例化成模板類:Compare<int> Compare<double> Compare<char> 實例化模板類對象:com1 com2 com3 */
//例6.8 類模板Stack的使用舉例。
#include<iostream.h> const int size=10; template<class T> //模板聲明,其中T為類型參數 class Stack{ //類模板為Stack public: void init() { tos=0; } void push(T ob); //聲明成員函數push的原型,函數參數類型為T類型 T pop(); //聲明成員函數pop的原型,其返回值類型為T類型 private: T stack[size]; //數組類型為T,即是自可取任意類型 int tos; }; template<class T> //模板聲明 void Stack<T>::push(T ob) //在類模板體外定義成員函數push { if(tos==size) { cout<<"Stack is full"<<endl; return; } stack[tos]=ob; tos++; } template<typename T> //模板聲明 T Stack<T>::pop() //在類模板體外定義成員函數push { if(tos==0) { cout<<"Stack is empty"<<endl; return 0; } tos--; return stack[tos]; } int main() { //定義字符堆棧 Stack<char> s1; //用類模板定義對象s,此時T被char取代 s1.init(); s1.push('a'); s1.push('b'); s1.push('c'); for(int i=0;i<3;i++){cout<<"pop s1:"<<s1.pop()<<endl;} //定義整型堆棧 Stack<int> s2; //用類模板定義對象s,此時T被int取代 s2.init(); s2.push(1); s2.push(3); s2.push(5); for(int i=0;i<3;i++){cout<<"pop s2:"<<s2.pop()<<endl;} return 0; } /* 程序運行結果是: pop s1:c pop s1:b pop s1:a pop s2:5 pop s2:3 pop s2:1 說明: (1)在每一個類模板定義之前,都需要在前面加上模板聲明,如 template<typename T> 或 tempplate<class T> 並且,類模板在使用時,必須在模板類名字后面綴上<類型參數> ,如 Stack<T> (2)如同模板函數一樣,模板類也可以有多個類型參數。 */
//例6.9 有兩個類型參數的類模板舉例
#include<iostream.h> template<class QQ,class T> //聲明模板,具有T1,T2兩個類型參數 class Myclass{ //定義模板類Myclass public: Myclass(QQ a,T b); void show(); private: QQ x; T y; }; template<typename QQ,typename T> Myclass<QQ,T>::Myclass(QQ a,T b) { x = a; y = b; } template<class QQ,class T> void Myclass<QQ,T>::show() { cout<<"x="<<x<<","<<"y="<<y<<endl; } int main() { Myclass <int,double>m1(12,0.15); //用類模板定義對象m1,此時T1,T2分別被int、double取代 Myclass <int,char*>m2(12,"This a test."); //用類模板定義對象m2,此時T1,T2分別被int,char*取代 m1.show(); m2.show(); return 0; } /* 程序運行結果是: x=12,y=0.15 x=12,y=This a test. */