C++圖文并茂分析講解模板
1.內容引入
? 不知道大家是否在高中時背過英語范文模板,以下就是博主的回憶:
? 這篇模板是一些英語比較好的老師寫的。
? 每當碰到感謝信時,我都會狂喜,盡管感謝的內容不同,地點不同,我都可以去根據模板,再根據作文分析模板的那些空對應應該填入什么。
其實呢c++中也用模板,但是這個時候,我們是寫模板的人,而編譯器變成了那個根據模板照葫蘆畫瓢的人
2.模板函數
C語言寫交換函數
#include<iostream> using namespace std; void Swapi(int* a, int* b) { int tmp = *a; *a = *b; *b = tmp; } void Swapd(double* a, double* b) { double tmp = *a; *a = *b; *b = tmp; } //…… int main() { int a = 1, b = 2; Swapi(&a, &b); double c = 1.1, d = 2.2; Swapd(&c, &d); return 0; }
? 要實現不同類型的交換,實參不僅要傳地址,而且不同類型的函數的名字要保持不同
至于為什么會這樣,大家可以去看看我的文章。解釋了為什么c語言不支持函數重載:
C++寫交換函數
#include<iostream> using namespace std; void Swap(int& x, int& y) { int tmp = x; x = y; y = tmp; } void Swap(double& x, double& y) { double tmp = x; x = y; y = tmp; } //…… int main() { int a = 1, b = 2; Swap(a, b); double c = 1.1, d = 2.2; Swap(c, d); return 0; }
? C++在語法上增加了引用和函數重載,在一定程度上彌補了c語言的不足,但是上述代碼明明邏輯很相似,卻還是要我們去實現不同類型的代碼,對于我們這種懶人來說,簡直就是煎熬
? 但是計算機他是一個任勞任怨的好鐵,不來不會感到疲勞,厭倦,是一個頭腦優(yōu)點笨笨的但是計算能力超強的大鐵塊。
模板交換函數的語法及其原理
語法
#include<iostream> using namespace std; template <class T> void Swap(T& x, T& y) { T tmp = x; x = y; y = tmp; } int main() { int a = 1, b = 2; Swap(a, b); double c = 1.1, d = 2.2; Swap(c, d); return 0; }
? 這樣寫交換函數是不是就輕松多了,但是我們思考以下,上述代碼調用的是一個Swap函數還是兩個Swap函數呢?
回顧我們說的模板,是我們寫的模板,然后編譯器照著模板幫我們寫出了int
和double
類型的交換函數。
原理
圖解:
我們也可以通過調試上述代碼,轉到反匯編,看看調用的函數是否真的是不同的函數。
理解顯示實例化和隱式實例化
我們那模板加法函數來理解
#include<iostream> using namespace std; T Add(const T& x,const T& y) { return x + y; } int main() { int a = 1, b = 2; double c = 1.1, d = 2.2; cout << Add(a, b) << endl;//編譯器要自己推類型的是隱式實例化 cout << Add(c, d) << endl; //cout << Add(a, c) << endl;//error這樣的寫法就錯了,為難編譯器了,編譯器也推不出來了 cout << Add<int>(a, c) << endl;//不需要編譯器去推的是顯示實例化 cout << Add<double>(b, d) << endl; cout << Add(a, (int)c) << endl; return 0; }
編譯器要自己去推T是什么類型的,就是隱式實例化
而由我們告訴編譯器T是什么類型的,就是顯示實例化
關于編譯器也是懶人這件事
我們來看幾道模板函數的代碼來看看編譯器是如何做事的:
#include<iostream> using namespace std; int Add(int left, int right) { return left + right; } // 通用加法函數 template<class T> T Add(T left, T right) { return left + right; } int main() { Add(1, 2); // 與非模板函數匹配,編譯器不需要特化 Add<int>(1, 2); // 調用編譯器特化的Add版本 return 0; }
? 如果調試了上述代碼就會發(fā)現,編譯器第一次調用的是第一個Add函數,第二次由于我們的指定,編譯器調用的是模板加法函數。
#include<iostream> using namespace std; int Add(int left, int right) { return left + right; } template < class T1, class T2> T1 Add(const T1 x,const T2 y) { return x + y; } int main() { Add(1, 2); Add(1, 2.0);//如果不寫模板,會進行一個類型轉換,再去調用第一個 return 0; }
3.類模板
由于c++的順序表是用vector表示的,下面咱們的類名也用vector表示
像以前我們實現一個順序表是這樣的。
typedef int VDateType; class vector { public: //…… private: VDateType* _a; size_t _size; size_t _capacity; }; int main() { vector v1; vector v2; return 0; }
但是我們無法讓v1
是int類型的順序表,v2
是double類型的順序表。
用模板類來實現
#include<iostream> #include<assert.h> using namespace std; namespace kcc { template<class T> class vector { public: vector() :_a(nullptr) , _size(0) , _capacity(0) {} // 拷貝構造和operator= 這里涉及深淺拷貝問題,還挺復雜,后面具體再講 ~vector() { delete[] _a; _a = nullptr; _size = _capacity = 0; } void push_back(const T& x) { if (_size == _capacity) { int newcapacity = _capacity == 0 ? 4 : _capacity * 2; T* tmp = new T[newcapacity]; if (_a) { memcpy(tmp, _a, sizeof(T) * _size); delete[] _a; } _a = tmp; _capacity = newcapacity; } _a[_size] = x; ++_size; } // 讀+寫 T& operator[](size_t pos); size_t size(); private: T* _a; size_t _size; size_t _capacity; }; // 模板不支持分離編譯,也就是聲明在.h ,定義在.cpp,原因后面再講 // 建議就是定義在一個文件 xxx.h xxx.hpp // 在類外面定義 template<class T> T& vector<T>::operator[](size_t pos) { assert(pos < _size); return _a[pos]; } template<class T> size_t vector<T>::size() { return _size; } } int main() { kcc::vector<int> v1; // int v1.push_back(1); v1.push_back(2); v1.push_back(3); v1.push_back(4); // v1.operator[](3); //cout << v1[3] << endl; //cout << v1[5] << endl; for (size_t i = 0; i < v1.size(); ++i) { v1[i] *= 2; } cout << endl; for (size_t i = 0; i < v1.size(); ++i) { cout << v1[i] << " "; } cout << endl; kcc::vector<double> v2; // double v2.push_back(1.1); v2.push_back(2.2); v2.push_back(3.3); v2.push_back(4.4); for (size_t i = 0; i < v2.size(); ++i) { cout << v2[i] << " "; } cout << endl; return 0; }
如果內部成員函數在類的外面定義的話,要加上類名::
當然了,本文章并不是重點介紹順序表vector的實現,而是讓大家看看類模板的效果
vector會在后續(xù)的文章中更新,敬請期待!
到此這篇關于C++圖文并茂分析講解模板的文章就介紹到這了,更多相關C++模板內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
C++中putchar與getchar函數的細節(jié)及運用
C語言提供putchar函數,用于給終端輸出一個字符;getchar函數,可以從終端接收用戶輸入的一個字符,本文給大家分享C++中putchar與getchar函數的細節(jié)及運用,感興趣的朋友跟隨小編一起看看吧2021-07-07C++中set/multiset與map/multimap的使用詳解
這篇文章主要為大家詳細介紹了C++中set/multiset與map/multimap的使用,文中的示例代碼講解詳細,具有一定的借鑒價值,需要的可以參考一下2023-02-02