前言
&emsp有句话是这么说的:世界是由懒人创造的,在我们的计算机世界中同样如此。我们之前说到,为了将同一个功能的实现简单化,我们学习了重载的相关知识,但是重载也有一个缺陷,就是需要将不同类型的变量所对应的函数一 一写出,就比如我们想要实现两个数的交换,那么问题来了,这个数有int、double、char等等类型,如果要满足任意类型的交换是不是要写好多的重载函数?那完全大可不必,为了方便绝大多数的“懒人”,C++便又推出了一项黑科技——模板,在定义函数时我们先不规定是什么类型的,只要你来我都可以接受,之后在调用时,我们再进行匹配,减少了太多的代码量了。下面我们来具体了解一下。
一.函数模板
1.函数模板的概念
&emsp模板函数正如它的名字一样,是一个函数系列的模板,该模板与函数的参数类型无关,它是根据实参类型的变化从而自动匹配产生特定的函数版本。
2.函数模板的使用方法
函数模板的使用是以template
关键词开头,在<>
中补充待定的参数类型,用typename
关键字来定义模板参数,也可以使用class
,但是不能使用struct
,参数一般用大写字母T
表示。
函数模板的书写格式:
template <typename T1,typename T2,…,typename Tn>
返回值类型 函数名称(参数列表)
{函数体}
函数模板的使用形式
- 单一的虚类型
- 多个虚类型
- 自动类型推导,如果用户没有显示声明, 编译器会自动判断数据类型,之后创建出相应的程序
- 显示指定参数;类型由用户指定,不用编译器推导。使用时要在函数名后面使用
<参数类型,参数类型>
的形式声明
举例
#include<iostream>
using namespace std;
//单一类型的参数
template <typename T>
T& MAX(T& num1, T& num2)
{
return num1 > num2 ? num1 : num2;
}
//多个虚类型
template <typename T1,typename T2>
void sum_1(T1 p1, T2 p2)
{
cout << p1 << '+' << p2 << '=' << p1 + p2 << endl;
}
int main()
{
int a = 20;
int b = 30;
double c = 3.25;
//单个类型,自动推导
int max = MAX(a, b);;//调用函数MAX,自动匹配出 int& MAX(int& num1,int& num2)的函数实体
cout << "the max number is " << max << endl;
//多个虚参数,自动推导
sum_1(a, c);
//多个参数,显示指定参数类型
sum_1<int, double>(3, 9.21);
sum_1<int, int>(3, 4);
return 0;
}
【参数的匹配原则】
- 一个非模板函数可以和一个同名模板一起存在而且该函数模板还可以被实例化为这个非模板函数。
- 对于非模板函数和同名函数模板存在一个优先匹配原则,意思是当其他条件相同时,在调动时会优先调用非模板函数。如果该模板可以产生一个具有更好匹配的函数,那么将选择模板。
- 模板函数不允许自动类型的转换,而普通函数可以进行自动类型转换。
类模板
类模板的形式与函数模板的使用方式类似。这里直接看格式
template<class T1,class T2,…,class Tn>
class 类名
{类体};
类模板举例
比如我们定义顺序表的类
#include<iostream>
using namespace std;
template<class T>//顺序表中存储的数据类型不唯一
class list{
public:
list(int n)
:_data(new T[n]),
_size(0),
_capacity(n)
{}
T list_at(size_t pos);//类外定义
private:
T* _data;
size_t _size;
size_t _capacity;
};
定义类外部接口
同样需要在外部进行泛型的声明,具体如下:
比如我们需要找到其中某一个位置的值
template<class T>
T list<T>::list_at(size_t pos)
{
return _data[pos];
}
类模板的实例化
int main()
{
list<int> ls(10);//在实例化时一定要显示声明类型
return 0;
}