C++圖文并茂分析講解模板
1.內容引入
? 不知道大家是否在高中時背過英語范文模板,以下就是博主的回憶:

? 這篇模板是一些英語比較好的老師寫的。
? 每當碰到感謝信時,我都會狂喜,盡管感謝的內容不同,地點不同,我都可以去根據(jù)模板,再根據(jù)作文分析模板的那些空對應應該填入什么。
其實呢c++中也用模板,但是這個時候,我們是寫模板的人,而編譯器變成了那個根據(jù)模板照葫蘆畫瓢的人
2.模板函數(shù)
C語言寫交換函數(shù)
#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;
}? 要實現(xiàn)不同類型的交換,實參不僅要傳地址,而且不同類型的函數(shù)的名字要保持不同
至于為什么會這樣,大家可以去看看我的文章。解釋了為什么c語言不支持函數(shù)重載:
C++寫交換函數(shù)
#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++在語法上增加了引用和函數(shù)重載,在一定程度上彌補了c語言的不足,但是上述代碼明明邏輯很相似,卻還是要我們去實現(xiàn)不同類型的代碼,對于我們這種懶人來說,簡直就是煎熬
? 但是計算機他是一個任勞任怨的好鐵,不來不會感到疲勞,厭倦,是一個頭腦優(yōu)點笨笨的但是計算能力超強的大鐵塊。
模板交換函數(shù)的語法及其原理
語法
#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;
}
? 這樣寫交換函數(shù)是不是就輕松多了,但是我們思考以下,上述代碼調用的是一個Swap函數(shù)還是兩個Swap函數(shù)呢?
回顧我們說的模板,是我們寫的模板,然后編譯器照著模板幫我們寫出了int和double類型的交換函數(shù)。
原理
圖解:

我們也可以通過調試上述代碼,轉到反匯編,看看調用的函數(shù)是否真的是不同的函數(shù)。

理解顯示實例化和隱式實例化
我們那模板加法函數(shù)來理解
#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是什么類型的,就是顯示實例化
關于編譯器也是懶人這件事
我們來看幾道模板函數(shù)的代碼來看看編譯器是如何做事的:
#include<iostream>
using namespace std;
int Add(int left, int right)
{
return left + right;
}
// 通用加法函數(shù)
template<class T>
T Add(T left, T right)
{
return left + right;
}
int main()
{
Add(1, 2); // 與非模板函數(shù)匹配,編譯器不需要特化
Add<int>(1, 2); // 調用編譯器特化的Add版本
return 0;
}? 如果調試了上述代碼就會發(fā)現(xiàn),編譯器第一次調用的是第一個Add函數(shù),第二次由于我們的指定,編譯器調用的是模板加法函數(shù)。
#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表示
像以前我們實現(xiàn)一個順序表是這樣的。
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類型的順序表。
用模板類來實現(xiàn)
#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;
}如果內部成員函數(shù)在類的外面定義的話,要加上類名::
當然了,本文章并不是重點介紹順序表vector的實現(xiàn),而是讓大家看看類模板的效果
vector會在后續(xù)的文章中更新,敬請期待!
到此這篇關于C++圖文并茂分析講解模板的文章就介紹到這了,更多相關C++模板內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
C++ Boost PropertyTree解析INI文件詳解
Boost PropertyTree庫不僅可以解析JSON,XML格式,還可以直接解析INI格式文件。這篇文章就是為大家介紹一下如何通過Boost PropertyTree解析INI文件,需要的可以參考一下2022-01-01
C語言函數(shù)傳遞數(shù)組和傳遞地址的區(qū)別你知道嗎
這篇文章主要介紹了C語言中數(shù)組作為函數(shù)的參數(shù)以及返回值的使用簡單入門,這里以一維數(shù)組作為基本條件進行例子講解,需要的朋友可以參考下2021-09-09
C++11中bind綁定器和function函數(shù)對象介紹
這篇文章主要介紹了C++11中bind綁定器和function函數(shù)對象介紹,綁定器,函數(shù)對象和lambda表達式只能使用在一條語句中,更多相關內容需要的小伙伴可以參考一下2022-07-07

