注意:本文中代碼均使用 Qt 開發編譯環境,如有疑問和建議歡迎隨時留言。
模板是 C++ 支持參數化程序設計的工具,通過它可以實現參數多態性。所謂參數多態性,就是將程序所處理的對象的類型參數化,使得一段程序可以用於處理多種不同類型的對象。
函數模板
函數模板的定義形式是:
template <class T> // or template <typename T> returnType functionName ( params ) { // todo something }
所有函數模板的定義都是用關鍵字 template 開始的,該關鍵字之后是使用尖括號 <> 括起來的類型參數表。每一個類型參數 T 之前都有關鍵字 class 或者關鍵字 typename,這些類型參數代表的是類型,可以是內部類型或自定義類型。這樣,類型參數就可以用來指定函數模板本身的參數類型和返回值類型,以及聲明函數中的局部變量。函數模板中函數體的定義方式與定義其它函數類似。
實例一:
#include <QCoreApplication> #include <QDebug> template < typename T > T abs(T x) { return x < 0 ? -x : x; } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); int n = -5; double d = -5.5; qDebug() << abs(n); qDebug() << abs(d); qDebug() << abs(d+n); return a.exec(); }
運行結果:

實例二:
#include <QCoreApplication>
//#include <QDebug> #include <iostream> using namespace std; template <typename T> void outputArray(const T *P_aaray,const int count){ for(int i=0; i < count; i++) { cout<<P_aaray[i]<<" "; } cout<<endl; } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); const int aCount = 8, bCount= 8, cCount = 20; int aArray[aCount] = {1,2,3,4,5,6,7,8}; double bArray[bCount] = {1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8}; char cArray[cCount] = "Welcometo see you!"; cout <<"a Array contains: "<<endl; outputArray(aArray,aCount); cout <<"b Array contains: "<<endl; outputArray(bArray,bCount); cout <<"c Array contains: "<<endl; outputArray(cArray,cCount); return a.exec(); }
運行結果:

函數模板幾點注意
① 如果在全局域中聲明了與模板參數同名的對象函數或類型,則該全局名將被隱藏。例如,在下面的例子中tmp 的類型不是 double 而是模板參數 Type :
typedef double Type; template <class Type> Type min( Type a, Type b ) { // tmp 類型為模板參數 Type // 不是全局 typedef Type tmp = a < b ? a : b; return tmp; }
② 在函數模板定義中聲明的對象或類型不能與模板參數同名
template <class Type> Type min( Type a, Type b ) { // 錯誤: 重新聲明模板參數 Type typedef double Type; Type tmp = a < b ? a : b; return tmp; }
③ 模板類型參數名可以被用來指定函數模板的返回位
// ok: T1 表示 min() 的返回類型,T2 和 T3 表示參數類型 template <class T1, class T2, class T3> T1 min( T2, T3 );
④ 模板參數名在同一模板參數表中只能被使用一次,但是模板參數名可以在多個函數模板聲明或定義之間被重復使用
// 錯誤: 模板參數名 Type 的非法重復使用 template <class Type, class Type> Type min( Type, Type ); // ok: 名字 Type在不同模板之間重復使用 template <class Type> Type min( Type, Type ); template <class Type> Type max( Type, Type );
⑤ 如果一個函數模板有一個以上的模板類型參數則每個模板類型參數前面都必須有關鍵字 class 或 typename
// ok: 關鍵字 typename和 class 可以混用 template <typename T, class U> T minus( T*, U ); // 錯誤: 必須是 <typename T, class U> 或 <typename T, typename U> template <typename T, U> T sum( T*, U );
⑥ 為了分析模板定義,編譯器必須能夠區分出是不是類型的表達式。對於編譯器來說它並不總是能夠區分出模板定義中的哪些表達式是類型(例如:如果編譯器在模板定義中遇到表達式 Parm::name 且 Parm 這個模板類型參數代表了一個類那么 name 引用的是 Parm 的一個類型成員嗎?)
template <class Parm, class U> Parm minus( Parm* array, U value ) { Parm::name * p; // 這是一個指針聲明還是乘法乘法? }
編譯器不知道 name 是否為一個類型。因為它只有在模板被實例化之后才能找到 Parm 表示的類的定義。為了讓編譯器能夠分析模板定義,用戶必須指示編譯器哪些表達式是類型表達式。告訴編譯器一個表達式是類型表達式的機制是在表達式前加上關鍵字 typename 例如如果我們想讓函數模板 minus() 的表達式 Parm::name 是個類型名因而使整個表達式是一個指針聲明我們應如下修改:
template <class Parm, class U> Parm minus( Parm* array, U value ) { typename Parm::name * p; // ok: 指針聲明 }
如上面的幾個例子中所示,關鍵字 typename 也可以被用在模板參數表中以指示一個模板參數是一個類型。
⑦ 如同非模板函數一樣,函數模板也可以被聲明為 inline 或 extern 的。此時,應該把指示符放在模板參數表后面而不是在關鍵字 template 前面。
// ok: 關鍵字跟在模板參數表之后 template <typename Type> inline Type min( Type, Type );
類模板
使用類模板使用戶可以為類聲明一種模式,使得類中的某些數據成員、某些成員函數的參數、某些成員函數的返回值能取任意類型(包括系統預定義的和用戶預定義的)。由於類模板需要一種或多種類型參數,所以類模板也常稱為參數化類。
類模板聲明的語法形式是:
template<模板參數表> class類名{ //類成員聲明 }
如果需要在類模板以外定義其成員函數,則需要采用以下形式:
template<模板參數表> 類型名類名<T>::函數名(參數表)
“模板參數表”由用逗號分隔的若干類型標識符或常量表達式構成,其內容包括:
(1)class 或 typename 標識符,指明可以接受一個類型的參數。
(2)類型說明符 標識符,指明可以接受一個由“類型說明符”所規定類型的常量作為參數。
“模板參數表”同時包含上述多項內容時,各項內容以逗號分隔。應該注意的是,模板類的成員函數必須是模板函數。
一個類模板聲明自身不產生代碼,他說明了類的一個家族。只有當它被其它代碼引用時,模板才根據引用的需要產生代碼。
使用一個模板類來建立對象時,應按如下形式聲明:
模板<模板參數表> 對象名1,…,對象名n;
使用實例:
#include <QCoreApplication> #include <QDebug> struct Student { int id; float gpa; }; template <class T> class Store{ public: Store(void); T GetElem(void); void PutElem(T x); private: T item; int haveValue; }; template <class T> Store<T>::Store(void) : haveValue(0) { } template <class T> T Store<T>::GetElem(void) { if (haveValue == 0) { qDebug() << "No item present!"; exit(1); } return item; } template <class T> void Store<T>::PutElem(T x){ haveValue++; item = x; } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); Student g ={1000,23}; Store<int> S1,S2; Store<Student> S3; Store<double> D; S1.PutElem(3); S2.PutElem(-7); qDebug() << S1.GetElem() << " " << S2.GetElem(); S3.PutElem(g); qDebug() << "The student id is "<< S3.GetElem().id; qDebug() << "Retrieving object D "; qDebug() << D.GetElem(); return a.exec(); }
輸出結果:

注意:本文中代碼均使用 Qt 開發編譯環境,如有疑問和建議歡迎隨時留言。
作者:趙者也
鏈接:http://www.jianshu.com/p/4c64d1b567a7
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
https://www.cnblogs.com/aademeng/articles/7265011.html