泛型编程
在C语言中,我们可以编写一个函数来交换数据,在C++中同样可以,并且我们可以根据函数重载,定义不同类型的交换函数,例如:
void Swap(int& left, int& right){
int tmp = left;
left = right;
right = tmp;
}
void Swap(double& left, double& right){
double tmp = left;
left = right;
right = tmp;
}
void Swap(char& left, char& right){
char tmp = left;
left = right;
right = tmp;
}
可以看到,如果我们想要交换数据就可以使用自定义的函数去实现,但是这里难免会有点不足
- 重载的函数仅仅只是类型不同,代码的复用率很低
- 代码的可维护性较低,要是一个出错那可能所有的重载都出错了
那么这个时候在C++中就可以去告诉编译器给它一个模板,让编译器在我们调用的时候就可以根据模板去自己生成并调用对应的函数
函数模板
定义模板需要用到template关键字,例如:
template<class T>
void Swap(T& left, T& right){
T temp = left;
left = right;
right = temp
}
(注意:class也可以换成typename)
当我们这样定义好了之后,就可以根据这个模板函数去实现对应的功能
可以看到,此时编译器就会根据我们传入的数据类型,自动识别并完成相对应的操作,非常的方便简洁
函数模板的概念
这个函数模板其实就有点像蓝图的概念,它本身并不是一个函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器
也就是在编译器编译阶段,编译器需要根据传入的实参类型来推演生成对应类型的函数然后才会去调用
例如上面的代码,就是将函数模板实例化了,编译器会先通过传入的实参a,判断出a是int类型,然后生成对应的int类型的函数在完成调用
模板参数的匹配原则
- 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数
- 对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板
- 模板函数不允许自动类型转换,但普通函数可以进行自动类型转换
也就是说假如现在有一个交换函数的模板,也有一个指定是int类型的交换函数,那么编译器会首先选择调用已有的函数。
像上面的情况就是,如果我们交换的是int类型,那么编译器就不会通过模板去生成调用函数了。
类模板
在C语言中,我们去定义一个类型时,通常我们会用typedef去改变一个内置类型的名称,以便于我们对数据类型的修改。
那么在C++呢,我们就可以通过一个类模板去定义不同数据类型的类
template<class T>
class Vector {
public:
Vector(size_t capacity = 10)
: _pData(new T[capacity])
, _size(0)
, _capacity(capacity)
{}
private:
T* _pData;
size_t _size;
size_t _capacity;
};
例如这样,我们就可以创建出一个类模板了,但我们需要这个类是什么类型时,只需要将类模板实例化即可
Vector<int> s1;
Vector<double> s2;
但是要注意,类模板的声明和定义要放在同一个源文件中,模板不能分离源文件定义。