一、函数模板
如果我们要写一个交换两个变量值的函数Swap,那么我们得对每一种类型都写一个,以便适用不同类型的参数,但是有了模板之后,可以简化操作
template<class T>
void Swap(T& x, T& y)
{
T tmp = x;
x = y;
y = tmp;
}
int main()
{
int a = 1, b = 3;
double c = 3.5, d = 6.8;
Swap(a, b);
Swap(c, d);
return 0;
}
在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然后产生一份专门处理double类型的代码,对于int类型也是如此。
函数模板的隐式实例化:让编译器根据实参推演模板参数的实际类型
函数模板的显式实例化:在函数名后的<>中指定模板参数的实际类型
二、类模板
如果我们实现一个栈,但是我们即想要存储int类型又想存double类型等等,如果没有模板,我们得创建多个栈用于适应不同的类型,这样会大大影响效率。我们也可以使用类模板,根据参数类型的不用调用合适的类。
例如栈:
template<class T>
class Stack
{
public:
Stack(size_t capacity = 3);
void Push(const T& data);
// 其他方法...
~Stack()
{
if (_array)
{
free(_array);
_array = nullptr;
_capacity = 0;
_size = 0;
}
}
private:
T* _array;
int _capacity;
int _size;
};
//类里声明,类外定义
template<class T>
Stack<T>::Stack(size_t capacity)
{
_array = new T[capacity];
_capacity = capacity;
_size = 0;
}
template<class T>
void Stack<T>::Push(const T& x)
{
_array[_size] = data;
_size++;
}
class Date
{
public:
Date(int year = 1)
:_year(year)
{}
private:
int _year;
};
int main()
{
Stack<int> s1; //int栈
Stack<double> s2; //double栈
Stack<Date> s3; //甚至有Date栈
return 0;
}
类模板的实例化:
类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。
//Stack类名,Stack<int>才是类型
Stack<int> s1;
Stack<double> s2;