交换两个数很简单,可以直接在函数里面交换,但如果不只是int类型,假如要交换的是double类型甚至是自定义类型呢?
也简单,直接把写好了的复制粘贴,在把类型改一改。
void SwapINT(int &x, int &y)
{
int tmp = x;
x = y;
y = tmp;
}
void SwapDOUBLE(double &x, double &y)
{
double tmp = x;
x = y;
y = tmp;
}
可以发现,我们要实现的函数极为相似,除了类型不同其他地方完全一样。那既然都差不多,有没有一种方式让编译器根据不同的类型来生成我们需要的函数呢?
为了提高效率,C++引进了函数模板来解决此类问题。
template <typename T>
void Swap(T &x, T &y)
{
T tmp = x;
x = y;
y = tmp;
}
这时候编译器就会根据传递的类型,来生成不同的函数。
比如这里想交换int就传int,想交换double型就传double型,想交换自定义类型就传自定义类型。
能够这样做的原因是,此时编译器也完成了一件事:函数模板的实例化。
void Test3()
{
int a = 0, b = 1;
double c = 1.1, d = 2.2;
Swap(a, b);
Swap(c, d);
}
当交换int型时,它会实例化成int类型的交换函数,也就是和上面的SwapINT函数没有任何区别,当交换bouble型时,它会实例化为double类型的交换函数,也就是上面的SwapDOUBLE函数
值得注意的是, Swap(a, b);和 Swap(c, d);他们不是同一个函数,这一点可以通过反汇编的角度证明:
如果是同一个函数,他们call的地址应当是相同的,但这里 Swap(a, b)它call的是Swap<int>的地址,Swap(c,d)它call的是Swap<double>的地址。很明显,他们调用的不是同一个函数。
那这里int型的a和double型的c能不能完成交换?
这些都是靠编译器自动去匹配识别类型,所以这种不明显的函数模板实例化叫做隐式实例化。所以a和c是无法完成交换的,因为他们的类型都无法匹配。
反之,显式实例化就是显式去传类型。
举个例子:
template<typename Type>
Type* func(int n=1)
{
Type *p = new Type[n];
return p;
}
void Test3()
{
func<int>(4);
}
func函数无法很好的匹配类型,所以func函数想要实例化只能通过显示实例化。
不仅仅是函数,类同样也可以使用模板。
下面用栈来做示范。
平时的栈都只能存一种数据类型,而C++的类模板可以实例化出各种不同类型的栈。
template <typename S>
class Stack
{
public:
Stack(int capacity = 4)
{
_a = new S[capacity];
_capacity = capacity;
_size = 0;
}
~Stack()
{
delete[] _a;
_a = nullptr;
_capacity = _size = 0;
}
private:
S *_a;
int _size;
int _capacity;
};
这样,对于各种类型的栈,都能够很好的被实例化出来。
不过类模板和函数模板在一些细节上还是有些差异:
在类和对象中,类名代表类型,类模板的实例化需要在类模板的名字后面加<>,在将实例化的类型放入<>里面,类模板的名字不是真正的类,真正的类是那个实例化的结果。
//Stack是类名,Stack<int>和Stack<double>才是类型
Stack<int> st1;
Stack<double> st2;
一个类里构造/析构函数的格式是类名+(),这也就不难解释为什么栈里面的构造/析构函数直接就是Stack(),而非Stack<>()。