类模板的定义
- 类模板定义的一般语法形式:
template <模板参数表> class 类名 {成员声明};
模板参数表解释参考函数模板解释。
例子:
template <class Type>
class Stack
{
public:
Stack(int cap);
~Stack() {delete []ele;}
void push(Type e);
Type pop();
bool empty() { return top == bottom;}
bool full() { return top == size-1; }
private:
Type* ele;
int top;
int size;
const static int bottom = -1;
};
类模板的实例化
同一个类模板用不同的类型实例化之后得到的类之间没有任何特殊的关系,类模板的每个实例都是一个独立的类型。类模板在实例化时必须显示地指定模板实参。在使用类模板时,模板名后面的尖括号时不可省略的。
Stack<int> is(20);
Stack<string> ss(10);
显示实例化
在大系统中,在多个文件中实例化相同模板的开销过大,C++11可以通过显示实例化来减少开销。
形式如下:
extern template 声明; //实例化声明
template 声明; //实例化定义
声明是一个类或函数声明,其中所有模板参数都已经被替换为模板实参。例如:
template class Stack<int>; //实例化定义
extern template class Stack<int>; //实例化声明
template int compare(const int&,const int&); //实例化定义
经过extern 修饰,相当于告诉编译器这个实例已经该程序的其他位置已经有该实例化的一个定义。对于一个给定的实例化版本,可以有多个extern声明,但是只能有一个定义。
extern 的作用类似定义全局变量时的作用。
类模板的成员数据
和非模板类一样,模板类的成员函数可以在类模板中定义,这时,该成员函数就是inline的。
成员函数也可以在类外定义,这是要指明它是一个类模板的成员函数。
即:template return-type class-name::func-name(parameters) { /…/}
例子:
template<class Type> Stack<type>::Stack(int cap)
{
assert( cap > 0);
size = cap;
ele = new Type[size];
top = bottom;
}
template<class Type> void Stack<Type>::push(Type e)
{
ele[++top] = e;
}
template<class Type> Type Stack<Type>::pop()
{
return ele[top--];
}
类模板的成员函数本身也是一个模板,当类模板被实例化时,成员函数并不自动实例化,只有当一个成员函数被调用时,它才被实例化。
Stack<string> ss(10);
while( !ss.full() )
{
string str;
cin >> str;
ss.push(str); //实例化成员函数push()
}
while(!ss.empty() )
cout << ss.pop() <<endl; //实例化成员函数pop()
类模板中还可以声明静态数据成员,静态数据成员的定义必须在类外。
类模板的每个实例都有自己的一套静态数据成员。
模板的代码组织
对类模板而言,类模板的定义和所有成员函数以及静态数据成员的定义必须完全被包含在每个要实例化该类模板的文件中。所以一般将类的完整定义(包括在类模板外定义的成员函数)都放在头文件中,在所有实例化模板的文件中都应该包含该头文件。
注意:为了避免模板定义被同一文件多次包含而引起编译错误,在模板定义的头文件中应该使用包含守卫:
#ifndef FLAG
#define FLAG
模板定义(包括成员函数的定义)
#endif