模板与泛型编程: 在C++中,模板是泛型编程的基础。模板是创建类或函数的蓝图或公式。
1. 模板
函数模板定义:函数模板是一个独立于类型的函数,可作为一种方式,产生函数的特定类型版本。面向对象编程所依赖的多态性称为运行时多态性,泛型编程所依赖的多态性称为编译时多态性或参数式多态性。
template <typename T>
int compare(const T &v1,const T &v2)
{
if(v1<v2) return -1;
if(v2>v1) return 0;
return 1;
}
特别注意,以上其实模板的定义,跟函数定义不同,不能在.h头文件里面声明,然后在.cpp里面定义。而是直接在.h里面定义函数模板。这点跟定义类相似。
函数模板使用:使用函数模板时,编译器会推断哪个(或哪些)模板实参绑定到模板形参。一旦编译器确定了实际的模板实参,就称它实例化了函数模板的一个实例。编译器使用实参代替相应的模板形参产生并编译该版本的函数。
类模板定义:
与调用函数模板形成对比,使用类模板时,必须为模板形参显式指定实参:Queue<int> qi;实质上,编译器用用户提供的实际特定类型代替Type,重新编写Queue类。
非类型模板形参:模板形参不必都是类型。本节将介绍函数模板使用的非类型形参。在调用函数是非类型形参将用值代替,值得类型在模板形参表中指定。例如,下面的函数模板声明了array_int是一个含有一个类型模板形参和一个非类型模板形参的函数模板。函数本身接受一个形参,该形参是数组的引用。
temple<Class T,size_t N> void array_init(T (&parm)[N])
{ for(size_t i=0;i!=N;++i){
parm[i]=0;
}
}
模板非类型形参是模板定义内部的常量值,在需要常量表达式的时候,可以使用非类型形参指定数组的长度。
当调用array_int时,编译器从数组实参计算非类型形参的值:
int x[42];
array_int(x);// array_init(int(&)[42])
编写泛型程序
在函数模板内部完成的操作限制了可用于实例化该函数的类型。程序员的责任是,保证用作函数实参的类型实际上支持所有的任意操作,以及保证在模板使用那些操作的环境中那些操作运行正常。编写模板代码时,对实参类型的要求尽可能少是很有益的。
2. 实例化
模板是一个蓝图,它本身不是类或函数。编译器用模板产生指定的类或函数的特点类型版本。产生模板的特定类型实例的过程称为实例化,这个术语反映了创建模板类型或模板函数的新实例的概念。模板在使用时将进行实例化,类模板在引用实际模板类类型时实例化,函数模板在调用它或用它对函数指针进行初始化或赋值时实例化。类模块的每次实例化都会产生一个独立的类类型。
当编译器看到模板定义的时候,它不立即产生代码。只有在看到用到模板时,如调用了函数模板或调用了类模板的对象的时候,编译器才产生特定类型的模板实例。
一般而言,当调用函数的时候,编译器只需要看到函数的声明。类似地,定义类类型的对象时,类定义必须可用,但成员函数的定义不是必须存在的。因此,应该将类定义和函数声明放在头文件中,而普通函数和类成员函数的定义放在源文件中。
模板则不同:要进行实例化,编译器必须能够访问定义模板的源代码。当调用函数模板或类模板的成员函数的时候,编译器需要函数定义,需要哪些通常放在源文件中的代码。(我把模板的定义全部放在了.h文件中)