C++ 初识模板
目錄
泛型編程
函數模板
類模板
非類型模板參數
?
-
泛型編程
若我們要寫一個swap交換函數,當交換的兩個變量為int型,swap函數的參數類型為int;當交換的兩個變量為double型,那么就要重載一個swap函數,參數變為double型。若出現新類型時,就需要增加對應的函數。這樣就使得代碼的可維護性變低,一出錯可能所有的重載均出錯。
要解決上面這個問題我們就要用到一種手段:模板。
泛型編程:編寫與類型無關的通用代碼,是代碼復用的一種手段。模板是泛型編程的基礎。
模板又分為:函數模板、類模板。
?
-
函數模板
函數模板代表了一個函數家族,該函數模板與類型無關,在使用時被參數化,根據實參類型產生函數的特定類型版本。
格式為:
? ? ? ? ? ? template<typename T1,....typename T2,typename T3>?(typename可以換為class,但不能使用struct代替class)
? ? ? ? ? ? 返回值類型 函數名(參數列表){}
//模板并不是函數,是編譯器用使用方式產生的具體類型函數的摸具 //編譯階段,編譯器根據傳入的實參類型來推演生成相對應的函數。 template<class T> void swap(T& a,T& b) {T tmp = a;a = b;b = tmp; } int main() {int a=0, b=1;double c=2.2, d=3.3;swap(a,b);swap(c,d); //兩者沒有調同一個swap,仍舊存在兩個swap,由編譯器生成 }函數模板的實例化就是用不同類型的參數使用函數模板。它又分為:隱式實例化、顯示實例化。
隱式實例化:讓編譯器根據實參推演模板參數的實際類型。
上述例子中若加一句 swap(a, c),這是不能通過編譯的。因為編譯期間,編譯器看到該實例化時,需要推演其 實參類型。通過a將T推演為int,通過c將T推演為double,但模板參數列表只有一個T,所以編譯器無法確定T的類型而報錯。
如果非要執行這句代碼,那要怎么辦呢?
? ? ?1.強轉:swap(a, (int)c);
? ? ?2.使用? 顯示實例化
顯示實例化:在函數名后的<>中指定模板參數的實際類型
上面的那句代碼就可以改為:swap<int>(a, c);
若類型不匹配,編譯器會嘗試進行隱式類型轉換,如果無法轉換成功編譯器將會報錯。
?
函數模板的匹配原則:
1.一個非模板函數可以和一個同名參數模板同時存在,而且該函數模板可以被實例化為這個非函數模板
2.如果非模板函數和模板函數條件相同,優先使用非模板函數,如果模板函數可以產生一個更好的匹配函數,那將選擇模板
3.顯示指定一個空的模板實參列表,該語法告訴編譯器自由模板才能匹配這個調用,而且所有的模板參數都應該根據實參演繹出來
4. 模板函數不允許自動類型轉換,但普通函數可以進行自動類型轉換
看看下面的測試代碼:
// 1.專門處理int的加法函數 int Add(int left, int right) { return left + right; }// 2.通用加法函數 template<class T> T Add(T left, T right) { return left + right; }// 3.通用加法函數 template<class T1, class T2> T1 Add(T1 left, T2 right) { return left + right; }void Test() { Add(1, 2); // 調 1Add<int>(1, 2); // 調 2Add(1, 2.0); // 調 3 Add<>(1, 2); // 調 2 }?
-
類模板
? ? ? ? 格式:
template<class T1,class T2,……class Tn> class 模板名 {//類成員變量 }? ? ? ? 例:
//實現一個簡單的動態順序表 //Vector不是具體的類,是編譯器根據被實例化的類型生成具體類的模具template<class T> class Vector { private:T * _pdata;int _size;int _capacity;public:Vector(size_t capacity):_pdata(new T[capacity]), _size(0), _capacity(capacity){}void PushBack(const T& data) { _pData[_size++] = data; }void popback(){--_size;}~Vector(); };// 注意:類模板中函數放在類外進行定義時,需要加模板參數列表 template <class T> Vector<T>::~Vector() { if(_pData) { delete[] _pData;} }類模板的實例化 :類模板實例化需要在類模板名字后跟<>,然后將實例化的類型放在<> 中即可,類模板名字不是真正的類,而實例化的結果才是真正的類。
例:
Vector<int> s1;
Vector<double> s2;?
?
-
非類型模板參數
就是用一個常量作為類(函數)模板的一個參數,在類(函數)模板中可將該參數當成常量來使用。
template<class T, size_t N = 10> class Array { private: T _array[N]; size_t _size; };注意:
1. 大部分非類型模板參數都是整形,浮點數、類對象以及字符串不能作為非類型模板參數的。
2. 非類型的模板參數必須在編譯期就能確認結果。
?
總結
- 上一篇: C++中引用的一些问题
- 下一篇: C++ 模板特化