1.函数模板
在C语言中实现一个加法的函数并不困难。
int add(int x, int y)
{
return x + y;
}
但是很明显,这个函数限定了两个相加的数都是整数,并且其返回值也为整数。但是,如果我们想得到两个双精度浮点数相加的结果呢?那么add函数可能就要写成:
int addint(int x, int y)
{
return x + y;
}
double adddouble(double x, double y)
{
return x + y;
}
那么,如果我们想实现其他的类型相加呢?很明显,这里我们就要写很多个不同名的函数了。这样写起来不方便,用起来也很不方便。
但是在C++中,提供了函数重载,这样就可以写同名函数了。所以在C++中可以写成下面的样子:
int add(int x, int y)
{
return x + y;
}
double add(double x, double y)
{
return x + y;
}
这样,使用的时候就可以直接调用add函数,而不是一堆不同名的函数了。
但是,面对不同的类型,我们依旧要写很多个函数来实现一个重复的功能,造成了很严重的冗余。
所以,C++提供了模板,也就是我们今天的主角。利用模板,我们可以把add函数写成这样:
template<class T>
T add(T x, T y)
{
return x + y;
}
其中,T是类型,其值由实参的类型决定,例如我们传入两个整数时,T就是int类型。
原理上,模板与宏类似,都是直接进行替换。所以在add函数中,编译器实际帮我们完成了一件非常简单的事情,就是针对不同的数据类型,将代码中的所有T替换为对应的类型。所以用不同的参数类型调用函数模板时,会根据参数的不同实例化出不同的函数。所以参数不同,调用的函数也不是同一个。
除了可以通过实际参数自动判断类型,也可以显示指定类型:
add<double>(1, 2.0)
而当两个实参不相同,且不指定类型时,将会报错:
add(1.0, 2)
因为T无法同时匹配double和int类型。
不过,模板参数可以有多个,以匹配不同的类型:
template<class T1,class T2>
void fun(T1 x, T2 y)
{
cout<<x<<' '<<y<<endl;
}
2.类模板
在C语言的学习中,我们曾经实现过链表、栈、队列等数据结构,它们为我们解决很多问题带来了便利。在C语言中,我们一般使用宏定义的方式来选择这些数据结构所保存的数据的类型。而在代码中,使用DataType替代数据的类型。
#define DataType int
这样,修改所保存的数据类型时,可以直接对宏进行修改,而不用对每一处进行修改了。
虽然这样很方便,但是无论怎么修改宏,我们都无法在一段代码中,同时使用一个数据结构来保存不同类型的数据。
为了解决上面的问题,同样也是为了更方便、快捷的使用数据结构,在C++中提出了类模板的概念。
我们可以利用模板,仅仅写一个栈,就可以保存不同类型的数据:
template<class T>
class stack
{
public:
//...
private:
T* _data;
//...
};
可以看出,与函数模板类似,只用将类型替换为模板参数,就可以只写一个栈,就能满足存储不同类型数据的需求。
而在使用时,与函数模板不同的是,类模板必须显示指定类型。因为类模板不能像函数模板一样通过实参的类型来推断模板参数的类型。
stack<int> st;//必须显示实例化