一、泛型編程html
——即實現一個通用的標準容器庫。算法
所謂通用的標準容器庫,就是要作到:比方List類存放所有肯恩類型的對象這樣的事;泛型編程讓你編寫一個全然通常化並可反覆使用的算法,其效率與針對某特定數據類型而設計的算法一樣。泛型便是指具備在多種數據類型上皆可操做的意思,與模板有些類似。編程
——泛型編程的表明做品STL是一種高效、泛型、可交互操做的軟件組件。數組
二、如何編寫一個通用的加法??安全
1》使用函數重載,針對每個所需一樣行爲的不一樣類型又一次實現它。函數
缺點:1》僅僅要有新類型出現。就要又一次加入相應函數。post
2》除類型外,所有函數的函數體都一樣,代碼的複用率不高。spa
3》假設函數僅僅是返回值類型不一樣,函數重載不能解決這個問題。設計
4》一個方法有問題。所有的方法都有問題,很差維護。指針
2》使用公共基類。將通用代碼放在公共基類裏面。
缺點:1》藉助公共基類來編寫通用代碼,將失去類型檢查的長處。
2》對於之後實現的很是多類,都必須繼承自某個特定的基類,代碼維護更加困難。
3》使用特殊的預處理程序。
缺點:1》不是函數,不進行參數類型檢查。安全性不高。
4》還可以使用泛型編程。
三、泛型編程:
1》編寫與類型無關的邏輯代碼。是代碼複用的一種手段。模板是泛型編程的基礎。
2》模板分爲:函數模板、類模板
四、函數模板:
1》函數模板表明了一個函數家族,在使用時被參數化,依據實參類型產生函數的特定類型。
2》函數模板的格式:
注意:1>typename是用來定義模板參數keyword,也可以使用class(建議儘可能使用typename)
2>但是不能使用struct
3》函數模板也可以定義成inline函數。(但是inline必須放在模板參數表以後,返回值以前,不能放在template以前)
4》模板是一個藍圖,它自己不是類或者函數,編譯器用模板產生特定的類或者函數的特定類型版本號,產生模板特定類型的過程稱爲函數模板實例化。
五、實參推演:
從函數實參肯定模板形參類型和值的過程叫作模板實參推演。多個類型形參的實參必須全然匹配。
六、類型形參轉換:
1》通常不會轉換實參來匹配已有的實例化,相反會產生新的實例。
2》編譯器僅僅會運行兩種轉換:
1>const轉換:接收const引用或者const指針的函數可以分別用非const對象的引用或者指針來調用
2>數組或者函數到指針的轉換:假設模板形參不是引用類型,則對數組或者函數類型的實參應該用常規指針轉換。數組實參將當作指向其第一個元素的指針,函數實參當作指向函數類型的指針。
七、模板參數:
1》函數模板有兩種類型的參數:模板參數和調用參數。
2》而模板參數又分爲:類型形參和非類型形參
3》模板形參名字僅僅能在模板形參以後到模板聲明或定義的結尾之間使用。遵循名字屏蔽規則。
4》模板形參的名字在同一模板形參列表中僅僅能使用一次。
5》所有模板形參前面必須加上class或者typenamekeyword修飾。
6》注意在函數模板內部不能指定缺省的模板實參。
八、非模板類型形參:
非模板類型形參是在模板內部定義的常量。在需要常量表達式的時候。可以使用非模板類型參數。
九、模板形參說明:
1》模板形參表使用<>括起來。
2》和函數參數表同樣。跟多個參數時必須用逗號隔開,類型可以一樣也可以不一樣。
3》模板形參表不能爲空。
4》模板形參可以是類型形參,也可以是非類型形參。類型形參跟在class和typename以後。
5》模板類型形參可做爲類型說明符用在模板中的不論什麼地方,與內置類型或本身定義類型的用法全然一樣。可用於指定函數形參類型、返回值、局部變量和強制類型轉換。
6》模板參數表中,class和typename具備形同的含義,可以互相交換。使用typename更加直觀。但是keywordtypename是做爲C++標準加入到C++中。就得編譯器可能不支持。
9+、模板函數重載:
注意:函數和所有的重載版本號的聲明都應該位域該函數被調用位置以前。
說明:
1》一個非模板函數可以和一個同名的函數模板同一時候存在。而且該函數模板可以被實例化爲這個非模板函數。
2》對於非模板函數和同名函數模板。假設其它條件都一樣,再調用時會優先調用非模板函數,而不會從該模板產生一個實例化。假設模板可以產生一個具備更好匹配的函數。那麼將選擇模板。
3》顯示指定一個空的模板實參列表。該語法告訴編譯器僅僅有姆安巴你才幹匹配這個調用。而且所有的模板都應該依據實參演繹出來。
4》模板函數不一樣意本身主動類型轉換,但普通函數可以進行本身主動類型轉換。
十、函數模板的特化:
模板函數特化形式例如如下:
1》keywordtemplate後面接一對空的尖括號<>
2》再接模板名和一對尖括號,尖括號裏指定這個特化定義的模板形參
3》函數形參表
4》函數體
注意:在特化以前。這個函數模板必須已經存在,而且二者形參個數同樣。
template<typename T> bool IsEqual(T left, T right) { return left == right; } template<> bool IsEqual<const char*>( const char * pleft, const char * pright) //這裏的<const char*>就至關於取代了T { return pleft == pright; } 十一、模板參數——適配器:stack(使用模板實現棧——後進先出) template <typename T> class SeqList { private : int _size ; int _capacity ; T* _data ; }; // template <class T, template<class> class Container> template <class T, template<class> class Container = SeqList> // 缺省參數 class Stack { public : void Push(const T& x ); void Pop(); const T& Top(); bool Empty(); private : Container<T > _con; }; void Test() { Stack<int> s1; Stack<int , SeqList> s2; }
模板的模板參數——實現隊列 template<typename T,template< typename T > class Containter> //再嵌套一個模板類型參數,,這裏的keyword必定是class————僅僅有類模板參數才幹指定缺省值 class Queue { public: Queue() {} void PushBack(const T& d) { _con.PushBack(); } void PopFront() { _con.PopFront(); } private: Containter<T > _con; }; int main() { Queue<int ,SeqList> q; q.PushBack(1); q.PushBack(2); q.PopFront(); return 0; }
十二、非類型的模板參數:
// 靜態順序表 //template<typename T, size_t MAX_SIZE> template <typename T, size_t MAX_SIZE = 10> //帶缺省模板參數 class SeqList { public : SeqList(); private : T _array [MAX_SIZE]; int _size ; }; template <typename T, size_t MAX_SIZE> SeqList <T, MAX_SIZE>::SeqList() : _size(0) {} void Test() { SeqList<int> s1; SeqList<int , 20> s2; }
1三、模板類:
模板類也是模板。必須以keywordtemplate開頭,後接模板形參表。
1四、模板類的實例化:
1》僅僅要有一種不一樣的類型。編譯器就會實例化出一個相應的類。
2》 SeqList<int > sl1 SeqList<double > sl2;當定義上述兩種類型的順序表時,編譯器會使用int和double分別取代模板形參。又一次編寫SeqList類,最後建立名爲SeqList<int>和SeqList<double>的類。
1五、類模板的特化:分兩種——局部特化、全特化
注意:全特化後定義成員函數,再也不需要模板形參
1》類型萃取
2》POD類型萃取
1六、模板的分離編譯:
——解決方法:
1》在模板頭文件 xxx.h 裏面顯示實例化->模板類的定義後面加入 template class SeqList<int >; 通常不推薦這樣的方法,一方面老編譯器可能不支持。還有一方面實例化依賴調用者。(不推薦)
2》將聲明和定義放到一個文件 "xxx.hpp" 裏面,推薦使用這樣的方法。
1七、模板總結:
——長處:
1》模板複用了代碼,節省資源,更快的迭代開發,C++的標準模板庫(STL)所以而產生。
2》加強了代碼的靈活性。
——缺點:
1》模板讓代碼變得凌亂複雜。不易維護,編譯代碼時間變長。
2》 出現模板編譯錯誤時,錯誤信息很是凌亂,不易定位錯誤。