一.什么是模板
模板也可以比作是一个模具,通过这个模具能做出很多个内容相同的东西。
单靠这样解释,很难解释的通,所以接下来举个例子的解释。
如果我们想要实现一个符合多类型的交换函数,我们可以使用函数重载来实现。如下:
#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;
}
void Swap(char& x, char& y)
{
char tmp = x;
x = y;
y = tmp;
}
虽然函数重载确实可以帮我们做到,但是这样做未免太麻烦了,相同逻辑的函数要写很多份,而且如果有新的类型需要实现这个功能,又要多写一份,这样做过于麻烦,那么有没有一个方法可以很好的解决呢,答案是模板。
二.函数模板
对于上面的问题,我们可以通过使用函数模板来实现,即把逻辑相同的函数写成一个模板,通过这个模板可以实现任何类型的交换。如下:
在上面的代码中,我们使用 template关键字来声明一个T类型,通过使用T类型的这个函数,在代码编译的时候,会自动实例化出不同类型的Swap函数,即最后T会被编译器替换成不同的类型,如:int、double、char等等,但是这个实例化是根据你的代码中所有的Swap函数来决定的,就是你写了几个类型的Swap函数,它就会实例化出对应的Swap类型函数。如下图
注意,程序在运行的时候,其实并没有去调用模板函数,而是调用了通过用模板函数实例化的对应的函数。
显式实例化
在上面的实例化模板函数中,均为模板的隐式实例化,即编译器自己推导,同时还有一个显式实例化,即自己先说明是哪个类型的。如下:
#include<iostream>
using namespace std;
template<class T>
void Swap(T& x, T& y)
{
T tmp = x;
x = y;
y = tmp;
}
int main()
{
int x1 = 10;
int y1 = 20;
double x2 = 1.11;
double y2 = 2.22;
Swap<int>(x1, y1);//显式实例化,指定实例化出int类型的Swap
Swap(x2, y2);//隐式实例化,编译器自己推导
return 0;
}
模板匹配原则
当非模板函数与模板函数同时存在并且条件相同时,会优先调用非模板函数 。
#include<iostream>
using namespace std;
template<class T>
void Swap(T& x, T& y)
{
T tmp = x;
x = y;
y = tmp;
}
void Swap(int& x, int& y)//调用这个函数
{
int tmp = x;
x = y;
y = tmp;
}
int main()
{
int x1 = 10;
int y1 = 20;
Swap(x1, y1);//优先调用非模板函数
return 0;
}
三.类模板
类模板也跟函数模板一样,可以根据类型去实例化出不同的类出来。
用过STL的应该都知道,比如想用数组来存储int数据时,要声明要存储的类型:vector<int>
所以类模板也是根据类型去实例化出不同的类。如下:
#include<iostream>
using namespace std;
//定义一个自己的栈
template<class T>
class Stack
{
public:
//栈的一系列操作
//…………
private:
T* _arr;//一个指向栈的指针
};
int main()
{
Stack<int> s1;//存放int类型的栈
Stack<double> s2;//存放double类型的栈
Stack<char> s3;//存放char类型的栈
return 0;
}
实例化过程如下图所示
学习的模板的初阶,我们就可以避免写很多重复逻辑的函数或者是类,这对大大提高了我们的编程效率,同时,使得类和函数用起来更加方便。