1.泛型函數
泛型編程:編寫與類型無關的通用代碼,是代碼復用的一種手段。模板是泛型編程的基礎。
2.函數模板
2.1函數模板的概念
函數模板代表了一個函數家族,該函數模板與類型無關,在使用時被參數化,根據實參類型產生函數的特定類型版本。
2.2函數模板格式
template<typename T1,typename T2...,typename Tn>//寫法1
返回值類型 函數名(參數列表)
{}
template<class T1,class T2... class Tn>//寫法2
返回值類型 函數名(參數列表)
{}
注意:typename是用來定義模板參數關鍵字,也可以使用class(切記:不能使用struct代替class)
template<class T>
void Swap(T& x, T& y)
{T tmp = x;x = y;y = tmp;
}
2.3函數模板的原理
函數模板是一個藍圖,它本身并不是函數,是編譯器用使用方式產生特定具體類型函數的模具。所以其實模板就是將本來應該我們做的重復的事情交給了編譯器
用函數模版生成對應的函數 -> 模版的實例化
在編譯器編譯階段,對于模板函數的使用,編譯器需要根據傳入的實參類型來推演生成對應類型的函數以供調用。比如:當用double類型使用函數模板時,編譯器通過對實參類型的推演,將T確定為double類型,然后產生一份專門處理double類型的代碼,對于字符類型也是如此。
2.4函數模板的實例化
用不同類型的參數使用函數模板時,稱為函數模板的實例化。模板參數實例化分為:隱式實例化和顯式實例化。
#include<iostream>
using namespace std;template<class T>
T Add(const T& x, const T& y)
{return x + y;
}int main()
{int a1 = 1;int b1 = 2;double a2 = 1.1;double b2 = 2.2;//隱式實例化,讓編譯器根據實參推演模板參數的實際類型cout << Add(a1, b1) << endl;cout << Add(a2, b2) << endl;//通過實參a1將T推演為int,通過實參a2將T推演為double類型,//但模板參數列表中只有一個T//編譯器無法確定此處到底該將T確定為int 或者 double類型而報錯//兩種處理方式:1.用戶自己來強制類型轉換 2.使用顯示實例化cout << Add(a1, (int)a2) << endl;//強轉cout << Add<int>(a1, a2) << endl;//顯式實例化return 0;
}
2.5 模板參數的匹配原則
- 一個非模板函數可以和一個同名的函數模板同時存在,而且該函數模板還可以被實例化為這個非模板函數
- 對于非模板函數和同名函數模板,如果其他條件都相同,在調動時會優先調用非模板函數而不會從該模板產生出一個實例。如果模板可以產生一個具有更好匹配的函數, 那么將選擇模板
#include<iostream>
using namespace std;template<class T>
T Add(const T& x, const T& y)
{return x + y;
}int Add(int x, int y)
{return x + y;
}int main()
{//與非函數模板類型完全匹配,不需要函數模板實例化Add(1, 2);//模板函數可以生成更加匹配的版本,編譯器根據實參生成更加匹配的Add函數Add(1, 2.2);return 0;
}
- 模板函數不允許自動類型轉換,但普通函數可以進行自動類型轉換
3.類模板
3.1模板的定義格式
template<class T1, class T2, ..., class Tn>
class 類模板名
{// 類內成員定義
};
3.2類模板的實例化
類模板實例化與函數模板實例化不同,類模板實例化需要在類模板名字后跟<>,然后將實例化的類型放在<>中即可,類模板名字不是真正的類,而實例化的結果才是真正的類。
// Stack是類名,Stack<int>才是類型
Stack<int> st1; // int
Stack<double> st2; // double
模版不建議聲明和定義分離到兩個文件.h 和.cpp會出現鏈接錯誤
#include<iostream>
using namespace std;template<class T>
class Stack
{
public://構造Stack(int n=4):_array(new T[n]),_size(0),_capacity(n){}//析構~Stack(){delete[] _array;_size = _capacity = 0;}//聲明void Push(const T& x);private:T* _array;size_t _size;size_t _capacity;
};//定義
//每個函數模板都得定義自己的模板參數
template<class T>
void Stack<T>::Push(const T& x)
{//擴容if (_size == _capacity){T* tmp = new T[_capacity * 2];memcpy(tmp, _array, sizeof(T) * _size);delete[] _array;_array = tmp;_capacity *= 2;}_array[_size++] = x;
}int main()
{//類名<類型> 變量Stack<int> st1;st1.Push(1);st1.Push(2);st1.Push(3);Stack<double> st2;st2.Push(1.1);st2.Push(2.2);st2.Push(3.3);return 0;
}