本期我们来学习C++的模板,我们本期只是简单学习,为后续做铺垫,未来会深入讲解
目录
函数模板
类模板
下面我们进入正题
我们之前学习了函数重载,有函数重载我们可以完成很多事情,比如交换两个变量
void Swap(int& left, int& right)
{
int temp = left;
left = right;
right = temp;
}
void Swap(double& left, double& right)
{
double temp = left;
left = right;
right = temp;
}
void Swap(char& left, char& right)
{
char temp = left;
left = right;
right = temp;
}
但是有一个问题,我们写了这么多交换函数,代码的重复率是非常高的
如果加上我们的自定义类,就会有无穷的交换函数,那真要写起来可就太难了
所以就有了模板,模板有函数模板和类模板
函数模板
template<typename T1, typename T2,......,typename Tn>
返回值类型 函数名(参数列表){}
这里的tyeoename也可以改为class,但是C++设计者觉得直接用class不好,后来引入typename
比如我们写一个交换模板
template<typename T>
void Swap(T& x1, T& x2)
{
T tmp = x1;
x1 = x2;
x2 = tmp;
}
调用模板和普通函数是一样的
我们这里调用了两个Swap,调用的不是同一个函数,而是编译器生成的,我们来证明一下
我们可以看到两个call是不一样的
这个过程就是模板的实例化,编译器根据传的参数不同,生成的函数也不同
另外,我们从此以后不用写swap,C++库里是有的,我们可以直接用
非常舒服
而且因为传的引用,指针也是可以交换的
模板是可以传多个参数的,在上面的格式上我们也可以看到
既然模板类型可以做参数,也就可以做返回值
这里就是使用模板参数做返回值
函数模板根据调用,自己推导模板参数的类型,实例化出对应的函数
模板参数可以用class和typename,但不可以用struct
我们说模板可以自动推导类型,但是有些情况它是推不出来的
比如这里,a给left,c给right,left要推成int,right要推成double,出现了冲突
我们可以用这种办法解决,让类型保持一致
或者这种办法,这种方法叫做显示实例化,这时候就不会通过传参推演,而是直接用指定类型实例化
多个参数也是同理
这是我们使用显示实例化的一个场景
另外,我们把const删掉,发现有些代码就编不过了
原因是类型转换会产生临时变量,临时变量具有常性,不能传给普通引用,要加const
类模板
这是我们之前写的栈,我们这里再次用它讲解知识
我们的栈现在只能存int类型,如果想存double类型的话,需要修改typedef int DateType
不过修改后我们就无法存别的类型了,如果我们想同时有一个存int类型的栈,一个存double类型的栈,就需要把这段代码拷贝一份,然后修改一下,如果我们有无数类型,就要拷贝无数份
但是如果有一天我们发现栈有bug,那么我们拷贝的所有栈都需要修改,那太麻烦了
所以我们就需要类模板来解决这个问题
我们把所有的DateType换成T即可,而且这里我们使用new来申请空间,比malloc更方便
使用显示实例化
我们来看类模板的定义格式
template<class T1, class T2, ..., class Tn>
class 类模板名
{
// 类内成员定义
};
类模板也是可以有多个参数的
多个参数时,使用加逗号即可,和函数模板是一样的
类模板的声明和定义分离和普通类不一样的,我们目前先不要分离到不同文件,我们后续会讲为什么,我们先分离到同一个文件里
对于普通类,类名和类型是一样的,但对于类模板,类名和类型是不一样的
对于类模板,Stack<int>这种才是类型
类模板定义分离后,要加上template,而且这里的类名是Stack,类型是Stack<T>
再比如我们把push拿出来,也是一样的
以上即为本期全部内容,希望大家可以有所收获
如有错误,还请指正