目录
1.泛型编程
现在我们来写一下交换函数。
void Swap(int& a, int& b)
{
int tmp = a;
a = b;
b = tmp;
}
void Swap(int& a, int& b)
{
int tmp = a;
a = b;
b = tmp;
}
void Swap(double& a, double& b)
{
double tmp = a;
a = b;
b = tmp;
}
void Swap(char& a, char& b)
{
char tmp = a;
a = b;
b = tmp;
}
以上三个都是我们常见的交换函数,当我们学C语言的时候,还没有函数重载,我们还不能这样写。学习了C++的时候,有了函数重载,我们可以写成这样。但是,感觉还是非常的麻烦,因为,他们的逻辑全都一样,就是类型不一样。那么有什么办法让它们当他们类型不同时,还可以写出相同的代码呢。
使用重载函数虽然可以实现,但是有以下几个不好的地方:
1.重载函数仅仅是类型不同,代码复用率较低,只要有新类型出现,就需要用户自己增加对应的函数,这还是比较麻烦的。
2.代码的可维护性比较低,一个出错可能所有重载函数都出错。
2.函数模版
C++提供了模版这一概念,很好的解决了以上问题。
函数模版概念
函数模版代表了一个函数家族,该函数模版与类型无关,在使用时被参数化,根据实参类型产生对应函数的特定类型版本。
函数模版格式
template<class T1,class T2,class T3,.......,Tn>
返回值类型 函数名(参数列表){}
下面我们使用模版来再写一个交换函数。
template<class T,class T>
void Swap(T a, T b)
{
T tmp = a;
a = b;
b = tmp;
}
以上就是我们写的交换函数的模版了,当我们使用不同类型的参数的时候,编译器会自动推导参数类型,进而推导出对应的函数。
注意:class是用来定义模版参数的关键字,也可以使用class(不能够用struct代替class)
函数模版的原理
函数模版是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模版就是将本来我们做的重复的事交给编译器了。
在编译器编译阶段,对于模版函数的使用,编译器需要根据传入的实参类型来推演生成对应的类型的函数以供调用。
函数模版的实例化
用不同类型的参数使用函数模版时,称为函数模版的实例化。函数参数实例化分为:隐式实例化和显式实例化。
1.隐式实例化:让编译器自动根据实参推演模版参数的实际类型
可以看到程序能通过编译,并且交换了a,b,c,d他们的值。
像这样,因为两个参数的类型不同,模版不知道将类型T推演成什么类型,所以编译器会报错。这个时候我们就需要进行类型转换。此时就有两种处理方式:1.用户自己来强制转化 2.使用显式实例化
2.显式实例化:在函数名后的<>中指定模版参数的实际类型
如果类型不匹配,编译器会尝试进行隐式类型转换,否则无法转换成功编译器报错。
模版参数的匹配原则
1.一个非模版函数可以和一个同名的函数模版同时存在,而且该函数模版还可以被实例化称为这个函数。
3.类模版
类模版定义格式
template<class T1,class T2,......,class Tn>
class 类模版名
{
//类成员定义
};
我们先简单来用类模版写一个栈。
template<class T>
class stack
{
public:
stack(size_t n)
{
_arr = new T[capacity];
_capacity = _capacity;
_top = 0;
}
private:
T* _arr;
int _capacity;
int _top;
};
需要注意的是,模版不建议声明和定义分离到两个文件.h和.cpp会出现链接错误
以上就是模版的一些基础知识了。