泛型編程就是以獨立於任何特定類型的方式編寫代碼,而模板是C++泛型編程的基礎.編程
所謂template,是針對「一個或多個還沒有明確的類型」所編寫的函數或類.函數
使用template時,能夠顯示的或隱示的將類型看成參數來傳遞.ui
下面是一個典型的例子,傳回兩數中的較大者:this
template<class T> inline const T& MAX(const T& a,const T& b) { return a>b?a:b; }
在這裏,第一行將T定義爲任意數據類型,於函數被調用時由調用者指定.spa
這個類型有關鍵字class引導,也可用typename引導,typename其實比class更直觀.指針
(須要注意的是,若是用到了嵌套依賴類型,則必需要用到typename).code
理解:對象
第一行template<class T>告訴編譯器:我在這兒定義了一個可變類型T,調用者使用什麼類型你就怎麼編譯吧!blog
缺省模板參數get
template class能夠有缺省參數,例如一下聲明,容許你使用一個或多個template來聲明MyClass對象:
template<class T,class container=vector<T> > class MyClass { public: MyClass(){} ~MyClass(){} protected: private: };
若是隻傳遞一個參數,那麼缺省參數可做爲第二參數使用:
MyClass<int> x1; // equivalent to: MyClass<int,vector<int> > x2;
注意:template缺省參數根據前一個(或前一些)參數而定義。這也就意味着若是參數傳遞列表中某個參數是缺省參數,那麼後面的全部參數都應該是缺省參數.
關鍵字typename
關鍵字typename被用來作爲類型以前的標識符號。考慮下面例子:
template<class SubType> struct BaseType { SubType a; }; template <class T> class MyClass1 { typename T::SubType *ptr; // ... };
這裏,typename指出SubType是class T中定義的一個類型,所以ptr是一個指向T::SubType的指針.
若是沒有typename,SubType將會被當成一個static成員,因而:
T::SubType * ptr;
會被解釋爲類型T中的兩個子成員SubType和ptr的乘積.
成員模板
class成員函數能夠是個template,可是這樣的成員template類型既不能是virtual,也不能有缺省參數,例如:
class MyClass { //... template<class T> void f(T); };
在這裏,MyClass::f聲明瞭一個成員函數,適用於任何類型參數.
這個特性經常使用來爲template class中的成員提供自動類型轉換,例以下面的例子中,assign()的參數x,其類型必須和調用端所提供的對象的類型徹底吻合:
template<class T> class MyClass { public: MyClass(); ~MyClass(); void assign(const MyClass<T>& x) // x must have same type as *this { value=x.value; } // ... protected: private: T value; };
若是使用了兩個類型,即便兩個類型之間能夠自動轉換,也會出錯:
void fun() { MyClass<double> d; MyClass<int> i; d.assign(d); // OK d.assign(i); // ERROR: i is MyClass<int> but MyClass<double> is required }
理解:
對於一個template class中的template成員,遵循「先入爲主」,若是第一次指定了類型,那麼後面都要和第一次保持一致.
但若是要指定兩個不一樣類型的類成員變量怎麼辦呢?
方法很簡單,咱們將成員變量在使用一個和class不一樣的template類型就行:
template<class T> class MyClass { public: MyClass(); ~MyClass(); template<class X> // member template void assign(const MyClass<X>& x) // allow different template types { value = x.getValu(); } T getValue() const { return value; } // ... protected: private: T value; }; void fun() { MyClass<double> d; MyClass<int> i; d.assign(d); // OK i.assign(i); // OK (int is assigned to double) }