一、模板的概念
模板相当于一个模子,编译器可以根据不同的类型利用该模子生成不同的代码,即模板实例化。
二、函数模板
函数模板代表一个函数家族,该模板与函数类型无关,在使用时编译器会根据实参类型实例化生成特定的函数类型版本。
函数模板格式:template <typename T1, typename T2, ...... ,typename Tn>
返回值类型 函数名(参数列表){ }
或者template <class T1, class T2, ...... ,class Tn>
当实现一个交换函数swap,对于不同的数据类型进行交换需要利用函数重载写不同的函数,这样的代码复用率比较低,可维护性也比较低。
void swap(int& a, int& b)
{
int tmp = a;
a = b;
b = tmp;
}
void swap(double& a, double& b)
{
double tmp = a;
a = b;
b = tmp;
}
void swap(char& a, char& b)
{
char tmp = a;
a = b;
b = tmp;
}
可以使用函数模板来解决这个问题
template<typename T>
void swap(const T& a, const T& b)
{
T tmp = a;
a = b;
b = tmp;
}
int main()
{
int a = 10, b = 20;
swap(a, b);
double c = 1.0, d = 2.0;
swap(c, d);
cout << a << " " << b << endl;
cout << c << " " << d << endl;
return 0;
}
三、函数模板的隐式实例化、显式实例化
用不同类型参数使用函数模板时,成为函数模板实例化。模板参数实例化分为:隐式实例化和显式实例化。
隐式实例化:让编译器通过实参类型推演模板参数的实际类型
然而当编译器通过实参推演出的模板参数实际类型不一致时,就会发生编译错误,如下:
解决这个问题就需要用户自己进行强制类型转换或者使用显式实例化
自己进行强制类型转换:自己进行强制类型转换时,编译器会生成一个临时变量,临时变量具有常性,所以函数模板参数需要用const修饰
显式实例化:在函数名后的<>指定模板参数的实际类型
四、模板参数的匹配原则
1.非模板函数和函数模板同时存在且都符合,调用非模板函数;非模板函数不符合则调用函数模板
Add(a1, a2)调用非模板函数
Add(b1, b2)调用函数模板
template<typename T>
T Add(T a, T b)
{
return a + b;
}
int Add(int a, int b)
{
return a + b;
}
int main()
{
int a1 = 10, a2 = 20;
double b1 = 1.0, b2 = 2.0;
Add(a1, a2);
Add(b1, b2);
return 0;
}
2.可以强制调用模板函数
Add<>(a1, a2)调用函数模板
Add<int>(a1, a2)调用函数模板
template<typename T>
T Add(T a, T b)
{
return a + b;
}
int Add(int a, int b)
{
return a + b;
}
int main()
{
int a1 = 10, a2 = 20;
double b1 = 1.0, b2 = 2.0;
Add<>(a1, a2);
Add<int>(a1, a2);
return 0;
}
五、类模板
类模板的定义格式:template<class T1, class T2, ...... ,class Tn>
class 类模板名 { 类内成员定义}
注意:当类模板中的函数进行类内声明、类外定义时,需要加上模板参数列表
template<class T>
class Vector {
private:
T* _pDate;
size_t _size;
size_t _capacity;
public:
//构造函数
Vector(size_t capacity)
:_pDate(new T[capacity])
,_size(0)
,_capacity(capacity)
{}
//析构函数(类内声明,类外定义)
~Vector();
//尾插函数(类内声明,类外定义)
void PushBack(const T& date);
//尾删函数(类内声明,类外定义)
void PopBack();
//......
size_t Size()
{
return _size;
}
};
template<class T>
Vector<T>::~Vector()//析构函数(类内声明,类外定义)
{
if (_pDate)
{
free(_pDate);
_pDate = nullptr;
}
}
template<class T>
void Vector<T>::PushBack(const T& date)
{
//...
}
template<class T>
void Vector<T>::PopBack()
{
//...
}
六、类模板的实例化
类模板实例化与函数模板实例化不同,类模板只能显式实例化。类模板名字不是真正的类,只有实例化的结果才是真正的类。
Vector是类名,Vector<int>是类型。
Vector<int> v1(4);
Vector<double> v2;