目錄
模板
一、定義:
模板是泛型編程的基礎。(泛型:任意類型)
泛型編程:編寫與類型無關的通用代碼,是代碼複用的一種手段。
二、分類:
模板分爲兩類:
- 函數模板
- 類模板
三、優缺點:
優點:
- 模板複用了代碼,節省資源,更快的迭代開發,C++的標準模板庫(STL)因此而產生。
- 增強了代碼的靈活性。
缺點:
- 模板讓代碼變得凌亂複雜且不易維護,編譯代碼時間變長。
- 模板編譯出錯時,錯誤信息非常凌亂,不易定位錯誤。
函數模板:
一、定義:
函數模板代表了一個函數家族,該函數模板與類型無關,在使用時被參數化,根據實參類型產生函數的特定類型版本。
編譯器根據傳入的實參類型,來推演生成對應類型的函數。
二、函數模板格式:
template <typename 形參名,typename 形參名,......>其中,typename 可以用 class 關鍵字代替。
返回類型 函數名(參數列表) {函數體}
三、函數模板的實例化
編譯器用模板產生指定的函數的特定類型版本,產生模板特定類型的過程稱爲函數模板實例化。函數模板必須由編譯器根據程序員的調用類型實例化爲可執行的函數。
模板參數實例化分爲:
- 隱式實例化:讓編譯器根據實參推演模板參數的實際類型 add(1,2)
- 顯式實例化:在函數名後的<>中指定模板參數的實際類型 add<int>(1,2)
例:add(1,2.0)
此時編譯器將報錯,因爲當模板參數類型不同且使用的是隱式實例化時,模板不會像普通的函數一樣進行隱式類型轉化
解決方法:
1. 用戶自己來強制轉化 add(1,(int)2.0)
2. 使用顯式實例化 add<int>(1,2.0)
編譯器只會執行兩種轉化
- 1、const轉換:接收const引用或者const指針的函數可以分別用非const對象的引用或者指針來調用
- 2、數組或函數到指針的轉換:如果模板形參不是引用類型,則對數組或函數類型的實參應用常規指 針轉換。數組實參將當做指向其第一個元素的指針,函數實參當做指向函數類型的指針。
四、函數模板的編譯
模板在這個過程中被編譯了兩次:
- ①實例化之前,檢查模板代碼本身,查看是否出現語法錯誤。
- ②在實例化期間,檢查模板代碼,查看是否所有的調用都有效,如:實例化類型不支持某些函數調用。
五、模板參數的匹配原則
- 1. 一個非模板函數可以和一個同名的函數模板同時存在,而且該函數模板還可以被實例化爲這個非模板函數。
- 2. 對於非模板函數和同名函數模板,如果其他條件都相同,在調動時會優先調用非模板函數而不會從該模 板產生出一個實例。如果模板可以產生一個具有更好匹配的函數, 那麼將選擇模板。
- 3. 模板函數不允許自動類型轉換,但普通函數可以進行自動類型轉換。
類模板:
一、格式:
template<class形參名,class形參名,…> class類名 { ... }; 其中,class可以用typename關鍵字代替。
類模板中函數放在類外進行定義時,需要加模板參數列表:
template <class T> Vector<T>::~Vector() { if(_pData) { delete[] _pData; } }
二、類模板的實例化
類模板實例化與函數模板實例化不同,類模板實例化需要在類模板名字後跟<>,然後將實例化的類型放在<> 中即可,類模板名字不是真正的類,而實例化的結果纔是真正的類。
// vector是類名,vector<int>纔是類型
vector<int> s1;
s1.PushBack(1);
s1.PushBack(2);
s1.PushBack(3);
三、類模板與函數模板的聯繫
- 類模板的成員函數都是函數模板
- 沒使用過的成員函數(即函數模板)不會被實例化
四、C++使用模板類的好處
- 可用來創建動態增長和減小的數據結構
- 它是類型無關的,因此具有很高的可複用性。
- 它在編譯時而不是運行時檢查數據類型,保證了類型安全
- 它是平臺無關的,可移植
- 可用於基本數據類型