1 类模板
1.1 类模板的声明
类模板的定义和实现都被放在头文件中,这点和函数模板类似。
Template<typename T>
Class Stack{
Private:
Std::vector<T> elems;
Public:
Stack();
Void push(T const&);
Void pop();
…
};
这个类的类型是Stack<T>,其中T是模板参数。所以,如果你要声明自己实现的拷贝构造函数和赋值运算符,那么应该这样写:
Template<typename T>
Class Stack{
Public:
Stack(Stack<T> const&);
Stack<T>& operator=(stack<T> const&);
…
};
当然,使用类名而不是类的类型时,就应该只使用stack,譬如,当你指定类的名称、类的构造函数、析构函数,就应该用Stack;
1.2 成员函数的实现
为了定义类模板的成员函数,你必须指定该成员函数是一个函数模板,而其你还需要使用这个类模板完整类型限定符。因此,类型Stack<T>的成员函数push()的实现如下。
Template<typename T>
Void Stack<T>::push(T const& elem)
{
Elems.push_back (elem);
}
对于类模板的任何成员函数,你都可以把它实现为内联函数,将它实现于类的声明里面。
1.3 类模板的使用
为了使用类模板,你必须显示的指定模板实参,类模板不会进行实参演绎,这点和函数模板有所不同。
只有那些被调用的成员函数,才会产生这些函数的实例化代码。对于类模板,成员函数只有在被使用的时候才会被实例化。显然,这样可以节省空间和时间;另一个好处是对于那些“未能提供所有成员函数中所有操作”的类型,你也可以使用该类型来实例化类模板,只要对那些“未能提供某些操作的”成员函数,模板内部不使用就可以了。
如果类模板中含有静态成员,那么用来实例化的每种类型,都会实例化这个静态成员。
如果用类模板来作为模板参数时,要注意尖括号的位置。
Stack<stack<int> > intStackStack;
1.4 类模板的特化
和函数模板的重载类似,通过特化类模板,你可以优化基于某种特定类型的实现,或者克服某种特定类型在实例化类模板时所出现的不足。另外,如果要特化一个类模板,你还要特化该类模板的所有成员函数,虽然也可以只特化某个成员函数,但这个做法并没有特化整个类,也就没有特化整个类模板。
特化的语法:
Template<>
Class Stack<std::string>{
…
};
在进行类模板的特化时,每个成员函数都必须重新定义为普通函数,原来模板函数中的每个T也相应的被进行特化的类型取代。
如:
Void Stack<std::string>::push (std::string const& elem)
{
Elems.push_back(elem);
}
注意到,在函数定义的前面,没有template<std::string>。
特化的实现可以和基本类模板的实现完全不同。
1.5 局部特化
类模板可以被局部特化,你可以在特定的环境下指定类模板的特定实现,并且要求某些模板参数仍然必须有用户来定义。
如:
Template<typename T1, typename T2>
Class MyClass{…};
可以被特化为:
Template<typename T, typename T>
Class MyClass<T, T>{…};
Template<typename T>
Class MyClass<T, int>{…};
Template<typename T1, typename T2>
Class MyClass<T1*, T2*>{…};
1.6 缺省模板实参
和函数模板不同,类模板的实参允许有缺省值。
比如对于上面定义的Stack,就可以有下面的实现。
Template<typename T, typename CONT= std::vector<T> >
Class Stack{
…
};