下面是多种类型的交换函数
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;
}
可以看出,虽然可以通过函数重载实现,但是代码的复用率底,只要有新的类型,就要用户自己增加对应的函数
所以C++中就引入了模板
只需要告诉编译器一个模子,编译器自己可以根据模板产生不同的代码
这就是泛型编程:编写与类型无关的通用代码,是代码服用的一种手段。
模板是泛型编程的基础,模板分为:函数模板和类模板
函数模板
函数模板与类型无关,在使用被参数化,根据实参类型产生函数的特定类型版本
函数模板格式:template<typename T1,typename T2,……>
typename是用来定义模板参数的关键字,也可以使用
class
:template<class T1,class T2,……>
template <typename T>
void Swap(T& x, T& y)
{
T tmp = y;
y = x;
x = tmp;
}
对于一个函数模板来说,其中定义的参数只对其下面的一个函数有作用,如果下面还要定义一个模板,还要重新定义模板参数
考虑一下,下面3个Swap
调用的是否为同一个函数:
int main()
{
int i1 = 1;
int i2 = 2;
Swap(i1, i2);
double d1 = 1.0;
double d2 = 2.0;
Swap(d1, d2);
char c1 = '1';
char c2 = '2';
Swap(c1, c2);
}
答案是:不是同一个函数,在经过编译器时,根据传入的实参类型来推演生成对应类型的函数
这一过程也被成为模板的实例化
函数模板的实例化又分为:隐式实例化和显式实例化
隐式实例化
隐式实例化就是让编译器根据实参类型推演模板参数的实际类型
template<class T>
T Add(const T& left, const T& right)
{
return left + right;
}
int main()
{
int a1 = 10, a2 = 20;
double d1 = 10.0, d2 = 20.0;
//隐式实例化
Add(a1, a2); //可以根据实参,推出模板参数类型为int
Add(d1, d2);//可以根据实参,推出模板参数类型为double
}
假如发生这样的实例化:
Add(a1, d1);
因为模板参数定义时只有一种类型T
,编译器推演类型时,通过实参a1
推演T
类型为int
,通过实参d1
推演出T
的类型为double
编译器无法确定到底是将T
确定为int
还是double
而报错
解决的办法有2中:
其一就是用户自己来强制类型转换:
Add(a1, (int)d1);
Add((double)a1, d1);
其二就是使用显式实例化
显式实例化
显式实例化时在函数名后的<>
中指定模板参数的实际类型
int main()
{
int i = 1;
double d = 2.0;
Add<int>(i,d);//显式实例化为int类型
Add<double>(i,d);//显式实例化为double类型
}
类模板
类模板的定义格式:
template<class T1,class T2,……>
class 类模板名
{
…………
}
需要注意的是:类模板中的成员函数全是模板函数
下面实现一个stack类模板:
template<class T>
class Stack
{
public:
Stack(int capacity= 4, int top = 0)
:_capacity(capacity)
, _top(top)
{
_a = new T[capacity];
}
private:
T* _a;
int _capacity;
int _top;
};
类模板的实例化:
Stack<int> st1;
Stack<double> st2;
关于类模板的类名和类型要注意:
普通类的类名与类型名相同
而模板类来说,类名是类名,类型是类型,是不一样的。
例如Stack类模板的类名:Stack
而类型是Stack<T>
以往普通类的成员函数在类外定义时,需要用作用作用域限定符标识这个函数属于哪个类。而对于类模板的成员函数在类外定义时,需要前面标识是属于哪个类型的
template<class T>
class Stack
{
public:
Stack(int capacity= 4, int top = 0)
:_capacity(capacity)
, _top(top)
{
_a = new T[capacity];
}
T Top();
private:
T* _a;
int _capacity;
int _top;
};
//类模板中成员函数在类外定义,需要加模板参数列表
template<class T>
T Stack<T>::Top()
{
return _a[top];
}