通常在调用普通函数时,我们只要做到将函数的声明放到其定义的前面,保证编译器先掌握到函数的声明,因此我们会把其函数声明放到头文件,而其定义放到源文件当中;但是模板不同,为了生成一个实例化版本,编译器需要掌握函数模板或类模板成员函数的定义,所以模板头文件通常既包括声明又包含定义。原因在于模板编译的一个特性:模板编译中,当编译器遇到一个模板定义时,它并不生成代码。只有当我们实例化出模板的一个特定版本时,编译器才会生成代码。
下面介绍:类模板
首先什么是类模板?
其实类模板是类的一个定义,可以用来定义一组特定类型的类。类模板用template关键字后接用尖括号(<>)括住、以逗号分隔的一个或多个模板形参的列表来定义。类模板针对仅数据成员和成员函数类型不同的类。
类模板的作用?
定义:
template <class T,class T,。。。>
返回类型 函数名(参数列表){
函数体
}
上面class关键字可以用typename关键字代替,效果是一样的。还有模板形参不能为空,一旦声明了类模板就可以用类模板的形参名声明类中的成员变量和成员函数,即可以在类中使用内置类型的地方都可以使用模板形参名来声明,如
template <class T>
class Stu{
public: T x;
T y;
T Scores(T a, T &b);
};
在类Stu中声明了两个类型为T的成员变量x和y,还声明了一个返回类型为T的带两个参数类型为T的函数Scores。
成员函数的实例化和注意项
#include <iostream>
using namespace std;
template <class numtype>
class Compare{
public :
Compare(numtype a,numtype b){
x=a;y=b;
}
numtype max(){
return (x>y)?x:y;
}
numtype min( ){
return (x<y)?x:y;
}
private :
numtype x,y;
};
int main( )
{
Compare<int > compare1(8,9);
cout<<compare1.max( )<<" 是最大值"<<endl;
cout<<compare1.min( )<<" 是最小值"<<endl<<endl;
Compare<float > compare2(36.6,12.82);
cout<<compare2.max( )<<" 是最大值"<<endl;
cout<<compare2.min( )<<" 是最小值"<<endl<<endl;
Compare<char> compare3('d','M');
cout<<compare3.max( )<<" 是最大值"<<endl;
cout<<compare3.min( )<<" 是最小值"<<endl;
return 0;
}
以上是声明一个类模板,利用它分别实现两个整数、浮点数和字符的比较,求出最大数和最小数。
上面列出的类模板中的成员函数是在类模板内定义的;如果改为在类模板外定义,不能用一般定义类成员函数的形式:numtype Compare::max( ) {.....} 而应当写成类模板的形式:
template <class numtype>
Compare<numtype> Compare<numtype>::max(){
return (x>y)?x:y;
}
因为我们在类模板外定义其成员时,我们并不在类的作用域中,直接遇到类名才表示进入类的作用域。上面template <class numtype>表示是类模板,后面的Compare <numtype>是一个整体,是带参的类。表示所定义的max函数是在类Compare <numtype>的作用域内的。在定义对象时,用户当然要指定具体的类型,进行编译时就会将类模板中的虚拟类型名numtype全部用实际的类型代替。