模板就是实现代码重用机制的一种工具,它可实现类型参数化,即把类型定义为参数, 从而实现了代码的可重用性。模版可以分为两类,一个是函数模版,另外一个是类模版。在使用模板概念时,经常会遇到这4个概念:函数模板,模板函数,类模板,模板类。这4个概念非常类似,也经常被我们所误用,本使用经验将主要讲述他们的差异。
这4个概念从汉语语法的角度考虑仅是语序的差异。对于函数模板和模板函数,函数模板应该强调的是模板,而模板函数应该强调的是函数。而对于类模板和模板类,类模板强调的应该是类的模板,而模板类强调的应该是一个类。
函数模板和模板函数
函数模板重点强调模板,函数仅仅是一个修饰词。所以函数模板指用于产生实例函数的模板。而模板函数重点在函数,模板是一个修饰词。所有模板函数应该是模板所生成的函数。函数模板特例化而生成的函数就是模板函数。
函数模板的一般定义形式如下:
template <class或typename T>
返回类型 函数名(形参表)
{
//函数定义体
}
说明
- template为声明模板的关键字,声明模板形参的关键字class或typename也不能省略,如果类型形不只一个 ,每个类型形参前都要加class, 类型形参表可包含基本数据类型可包含类类型。
- 在函数模板被调用时,编译器根据实际参数的类型确定模板参数T的类型,并自动生成一个对应的函数,即模板函数。模板参数的类型不同,生成的模板函数也不同。
- 模板函数类似于重载函数,但两者还是有很大差异:函数重载时,每个函数体内可以执行不同的动作,但同一个函数模板实例化后的模板函数都必须执行相同的动作。
模板函数是由函数模板实例化生产的具体函数,上述函数模板生成的模板函数的一般形式为:
返回类型 函数名<数据类型参数标识符>(形参表)
{
//函数定义体
}
下面是一例,函数模板的定义和使用的例子:
#include <iostream.h>
// 定义绝对值求值函数模板
template <class T>
T abs(T val)
{
return (val<0) ? -val : val;
}
int main()
{
int i = 100;
cout << abs(i)<< endl; //类型参数T替换为int
long l = -12345L;
cout << abs(l) << endl; //类型参数T替换为long
float f = -125.78F;
cout << abs(f) << endl; //类型参数T替换为float
return 0;
}
不仅如此,函数模板亦可使用多个类型参数,每个类型参数前面均需加关键字class或typename,其间用逗分隔,其形式如下所示:
template <class T1, class T2, class T3>
下面是一例,使用多类型参数的函数模板:
#include <iostream.h>
// 求最大值函数模板
template <class T1,class T2>
T1 Max(T1 x, T2 y)
{
return x>y ? x: (T1)y;
}
int main()
{
int i = 100;
float f = -125.78F;
cout << Max(i,f) << endl; //类型参数T1替换为int,T2替换为float
return 0;
}
类模板和模板类
类模板和模板类的关系与函数模板和模板函数类似。类模板强调模板,由此类模板生成的具体类,称之为模板类。类模板的定义如下:
template <class或typename T>
class 类名
{
// 类定义......
};
说明
- template是声明各模板的关键字,表示声明一个模板,模板参数可以是一个,也可以是多个。
- 在类中凡是采用标准数据类型的数据成员,函数成员的参数都必须加上类型标识符;返回类型也是如此。
- 如果类的成员函数在类声明之外定义,则类的成员函数声明必须是函数模板形式,其定义形式如:template <class T> 返回类型 类名::函数名(T 形参1,……)。
将类模板实例化后生成的具体类是模板类。模板类的一般形式为:
类名<T> 对象1, 对象2, …, 对象n;
下面是一个堆栈模板类:
// 堆栈模板类
template <class T>
class Stack
{
public:
Stack()
{
m_nPos= 0;
}
virtual ~Stack()
{}
// 压栈函数
void Push(T value);
// 出栈函数
T Pop();
// 判断堆栈是否为空
bool IsEmpty()
{
return m_nPos == 0;
}
// 判断堆栈是否还有元素存在
bool HasElement()
{
return !IsEmpty();
}
// 判断堆栈是否已满了。
bool IsFull()
{
return m_nPos == STATCK_SIZE;
}
private:
const static int STATCK_SIZE = 100;
//使用常量表示堆栈的大小
int m_nPos;
// 堆栈数据缓存区。
T m_Data[STATCK_SIZE];
};
// 压栈函数
template <class T>
void Stack<T>::Push(T value)
{
//使用后置递增操作符
m_Data[m_nPos++] = value;
}
// 出栈函数
template <class T>
T Stack<T>::Pop()
{
//使用前置递减操作符
return m_Data[--m_nPos];
}
根据以上的分析,我们可等到这样的结论:类模板和函数模板都是实例化之前的工具,模板类和模板函数都是实例化的产物。
请谨记
- 掌握类模板和模板类及函数模板和模板函数的差异,首先你需要明白各自强调的重点。
- 类模板和函数模板强调模板。模板类和模板函数强调具体类和函数。