模板分了两种:函数模板和类模板
函数模板
背景:怎么实现一个通用的交换函数?不用函数重载,只写一个函数。
引入泛型编程——模板
代码如下:
template<class Y>
//template<typename Y>//也可以用typename,在这个位置没有区别,不能用struct
void Swap(Y& x, Y& y)
{
Y tmp = x;
x = y;
y = tmp;
}
//也可以定义多个模板参数
template<class Y,class X>
void Func()
{
}
int main()
{
int a = 1, b = 2;
Swap(a, b);
double c = 1.0, d = 2.0;
Swap(c, d);
return 0;
}
但是,实际调用函数的地址并不同,调用的不是模板,调用的是模板实例化生成的代码。模板没有减少函数。如下图:
模板的原理是把这份工作交给了编译器去做。
模板的实例化
模板的实例化分为显示实例化和隐式实例化,代码如下:
template<class T>
T Add(const T& left, const T& right)
{
return left + right;
}
int main()
{
int a = 1, b = 2;
double c = 1.2, d = 2.2;
//实参传递给形参,自动推演模板类型
Add(a, b);
Add(c, d);
Add(a, (int)c);
Add((double)b, d);
//显示实例化
Add<int>(a, c);
Add<double>(b, d);
return 0;
}
模板参数的匹配原则:
1. 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数。
2. 对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数,那么将选择模板。
类模板
背景:为什么不用typedef,而引入类模板?
因为typedef不能同时让栈A存int,让栈B存double,除非同时写int栈和double栈。
template<class T>
class Stack
{
public:
Stack(int capacity = 4)
{
_a = new T[capacity];//不用检查是否失败
_top = 0;
_capacity = capacity;
}
~Stack()
{
delete[] _a;//匹配使用
_capacity = _top = 0;
}
private:
STData* _a;
size_t _top;
size_t _capacity;
};
int main()
{
//Stack叫类名,Stack<int>叫类型
Stack<int> stA;//类模板只能显示实例化使用
Stack<double> stA;
return 0;
}
如果类模板的声明和定义分离,就要写成如下,要指定类名、类型,还要加上模板参数,例如:
template<class T>
Stack<int>::~Stack()
{
delete[] _a;//匹配使用
_capacity = _top = 0;
}
类模板声明和定义要放在同一个文件中,如果分成两个文件(比如.h和.cpp),会出现链接错误。