作者介绍:
关于作者:东条希尔薇,一名喜欢编程的在校大学生
主攻方向:c++和linux
码云主页点我
本系列仓库直通车
作者CSDN主页地址
印刷术是中国四大发明之一,它极大地便利了古代人对于读书的需求。
设想,如果我们没有印刷术的话,我们要传播书籍该怎么做?我们必须要把这本书亲自手抄几万份后传播,这样的传播方式不仅非常的繁琐,而且浪费了很多不必要的人力
我们有印刷术就会方便许多,我们只需要抄一遍书上的内容,把它抄在一个模子上,然后使用这个模板,就能很轻松的把它复印几万份
而我们今天讲的内容,和古代的印刷术有异曲同工之妙
函数模板提出背景
假如我们要实现一个函数,这个函数要实现两个变量的交换,我们可以轻松写出以下代码
void Swap(int& rx,int& ry)
{
int tmp=rx;
rx=ry;
ry=tmp;
}
但这个函数会有一个问题:我们只能交换整数类型,那么我们要交换其它类型的数又该怎么办呢?
我们可能想到,把每个类型都写一遍不就行了?
void Swap(int& rx,int& ry)
{
int tmp=rx;
rx=ry;
ry=tmp;
}
void Swap(float& rx,float& ry)
{
float tmp=rx;
rx=ry;
ry=tmp;
}
void Swap(double& rx,double& ry)
{
double tmp=rx;
rx=ry;
ry=tmp;
}
这样每个类型写一个函数,会造成大量的代码冗余,而且对于自定义类型,我们根本不能确定到底要写多少个这样的函数
所以,在c++里面引入了函数模板的概念
函数模板的概念与使用
函数模板代表了一个函数家族,该函数模板与类型无关,它会根据实参自动推导自己的参数类型
拥有模板也是c++能支持泛型编程的基础,它也是STL实现的基础
使用格式:
template<class T1,class T2,.....class Tn>
//或者是typename T1....
//T1作为模板名,可以随意修改,不过一般都用T来表示
在上面一行代码完成后,下面要立即跟上一个模板函数
我们有了函数模板,就能让上面的swap函数支持任意类型,并且只有一份函数源码
template<class T>
void swap(T& rx,T& ry)
{
T tmp=rx;
rx=ry;
ry=tmp;
}
函数模板原理及其实例化
我们知道了函数模板能够实现所有类型的使用,那么函数模板算一个函数吗?
我们可以通过观察不同类型函数的地址来观察
观察其反汇编代码
我们可以观察到,每次调用函数时,对应的swap函数地址是不一样的
我们可以得出结论,模板函数并不是一个函数
函数模板需要通过实例化来让对应参数使用其函数
实例化:模板函数根据不同的参数类型,来推演出它的参数类型,然后专门处理出一个针对此类型的函数代码
而实例化方式分为两种:隐式实例化,显式实例化
隐式实例化
编译器根据实参,自动推导出参数的实际类型
template<class T>
void Swap(T& x, T& y)
{
T tmp = x;
x = y;
y = tmp;
}
int main()
{
int a = 2;
int b = 3;
float c = 3.3f;
float d = 4.4f;
Swap(a, b);
Swap(c, d);
return 0;
}
但注意:不能把不同类型的参数传入一个函数模板中,这样编译器就不知道这个模板到底推导成什么类型了
Swap(a,d);//int和float类型混合,报错
显式实例化
在函数名后加上**<类型名>**
Swap<int>(a,b);
Swap<int>(a,d);//这里不同类型使用不会报错,而是会发生隐式类型转换为<>内的类型
实例化原则:
对于非模板函数和函数模板同名的情况,调用时如果类型与非模板参数完全相同,将会优先调用非模板函数
void Swap(int& x, int& y)
{
int tmp = x;
x = y;
y = tmp;
}
template<class T>
void Swap(T& x, T& y)
{
T tmp = x;
x = y;
y = tmp;
}
int main()
{
int a = 2;
int b = 3;
float c = 3.3f;
float d = 4.4f;
Swap(a, b);//调用非模板
Swap(c, d);//调用模板
return 0;
}
类模板
与函数模板类似,并不是一个真正的类型,而是根据不同类型推导出来的
使用方式:在类最上面使用template,类内部参数可以使用其模板
template<class T>
class Stack//栈类
{
public:
void push(T n)
{
arr[top]=n;
top++;
size++;
}
private:
T *arr;
int tmp;
int cap;
}
注意以下几点
如果类成员函数在类外实现,必须要在每个函数前面加上template
类模板只能显式实例化