C++现在支持两种基本类型的模板:类模板和函数模板(实际上还包括成员模板)。
虚成员函数
成员函数模板不能被声明为虚函数。因为虚函数调用机制的普遍实现都使用了一个固定大小的表,每个虚函数都对应表的一个入口。然而,成员函数模板的实例化个数,要等待整个程序都翻译完毕才能确定,这就和表的大小(是固定的)产生了冲突。如果要支持虚成员函数模板,将需要一种全新的C++编译器和链接器的机制。
相反,类模板的普通成员(不是模板的成员)可以是虚函数,因为当类被实例化之后,它的个数是固定的:
template<typename T>
class Dynamic{
public:
virtual ~Dynamic(); //OK,每个Dynamic只对应一个析构函数
template<typename T2>
virtual void copy(T2 const &); // error:在确定Dynamic<T>的实例的时候,并不知道copy()的个数
};
模板的链接
每个模板都必须有一个名字,而且在它所属的作用域下,该名字必须是唯一的;除非函数模板可以别重载。注意,类模板不能和另外一个实体共享一个名称,这一点和clas类型是不一样的。
int C;
class C; // ok,类名称和非类名称位于不同的名字空间
int X;
template<typename T>
class X; // error:和变量X冲突
struct S;
template<typename T>
class S; // error:和变量truct S冲突
模板名字是具有链接的,但它们不能具有C链接。但我们在大多数情况下所说的是标准的链接,同时也存在非标准的链接,它们可以具有一个依赖于实现的含义。如下:
extern "C++" template<typename T>
void normal(); // 这是缺省情况,上面的链接规范可以不写
extern "C" template<typename T>
void isvalid(); // 错误:模板不能有C链接
extern "Xroma" template<typename T>
void xroma_link(); // 非标准的,但某些编译器将来可能支持Xroma语言的链接兼容性
模板通常具有外部链接。唯一的例外就是前面有static修饰符的名字空间作用域下的函数模板:
template <typename T>
void external(); // 作为一个声明,引用位于其他文件的,具有相同名称的实体;即引用位于其他文件的external()函数模板,也叫做前置声明
template <typename T>
static void internal(); // 与其他文件中具有相同名称的模板没有关系(即不是外部链接)
又由于外部链接,不能在函数内部声明模板
基本模板
如果模板声明的是一个普通声明,我们就称它声明的是一个基本模板。这类模板声明是指:没有在模板名称后面添加一对<>
(和里面的实参)的声明
template<typename T> class Box; //正确:基本模板
template<typename T> class Box<T>; // error
template<typename T> void translate(T*) // 正确:基本模板
template<typename T> void translate<T>(T*) // error