泛型编程与面向对象编程一样,都依赖于某种形式的多态性。面向对象编程所依赖的多态性称为运行时多态性,泛型编程所依赖的多态性称为编译时多态性或者参数式多态性。

在泛型编程中,我们所编写的类和函数都能多态地用于跨越编译时不相关的类型,一个类或者一个函数可以用来操纵多种类型的对象。标准库中的容器、迭代器和算法是很好的泛型编程的例子。

模板是泛型编程的基础。

模板函数的例子

首先来看一段用于比较大小的代码。

#include<iostream> using namespace std; int compare(const int &v1,const int &v2); double compare(const double &v1,const double &v2); int main() { 	cout<<"Hello"<<endl; 	cout<<compare(1,2)<<compare(1.2,3.2)<<endl; 	    return 1; } int compare(const int &v1,const int &v2) { 	cout<<"compare int"<<endl; 	if (v1<v2) return -1; 	if(v2<v1) return 1; 	return 0; } double compare(const double &v1,const double &v2) { 	cout<<"compare double"<<endl; 	if (v1<v2) return -1; 	if(v2<v1) return 1; 	      return 0; }

编译运行之后的结果如下:

再学C++ Primer(11)-模板与泛型编程

上面的程序中,compare函数被重载,由于参数不同,最终调用的函数会自动匹配。

现在假设我需要compare函数不仅要支持int和double,还要支持float,string…继续重载么,No。现在就需要模板函数了。

对源程序进行修改。

#include<iostream> #include<string> using namespace std; template <typename T> int compare(const T &v1,const T &v2) { 	if(v1<v2) return -1; 	if(v1>v2) return 1; 	return 0; } int main() {     cout<<"Hello"<<endl;     string a="zoo",b="tiger";     cout<<compare(a,b)<<compare(1,2)<<compare(1.2,3.2)<<endl;     return 1;  }

运行结果:

再学C++ Primer(11)-模板与泛型编程

这就是传说中的模板函数了,使用函数模板时,编译器会推断哪个模板实参绑定到模板形参。一旦编译器确定了实际的模板实参,就称它实例化了函数模板的一个实例。

编译器使用实参代替相应的模板形参并编译改版本的函数。

所以上面实际是编译了三个compare的版本。脏活累活编译器已经帮我们干了。

使用的时候要注意用作模板形参的名字不能在模板内部重用。

载函数模板内部完成的操作限制了可用于实例化改函数额度类型。程序员的责任是:保证用作函数实参的类型实际上支持所用的任意操作,以及保证在模板使用那些操作的环境中那些操作运行正常。

在使用模板的时候要注意以下几点:

1)对实参类型的要求尽可能少;

2)模板形参是const引用;

3)函数体中的测试只用<比较。

用template inline替代#define

我们常用#define来定义宏,比如:

#define CALL_WITH_MAX(a,b) f((a)>(b))?(a):(b);

上面的语句虽然很小心地打了很多小括号,但是…如果语句是这样:

 int main()   {       int a=5,b=3;       CALL_WITH_MAX(++a,b);       cout<<"a"<<a<<"b"<<b<<endl;       CALL_WITH_MAX(++a,b+10);       cout<<"a"<<a<<"b"<<b<<endl;       cout<<"Hello"<<endl;       return 1;   } 

运行后的结果会是这样:

再学C++ Primer(11)-模板与泛型编程

第一次调用CALL_WITH_MAX,a加了两次,第二次a只加了一次,所以,还是不安全。

下面用模板来实现一下。

#include<iostream> using namespace std; //#define CALL_WITH_MAX(a,b) (a)>(b)?(a):(b); template <typename T> inline T call_with_max(const T &a,const T &b) { 	return(a>b?a:b); } int main() { 	int x,a = 5,b = 3; 	x = call_with_max(++a,b); 	cout<<"a"<<a<<"b"<<b<<"x"<<x<<endl; 	x = call_with_max(++a,b+10); 	cout<<"a"<<a<<"b"<<b<<"x"<<x<<endl; 	return 1; }

运行结果:

再学C++ Primer(11)-模板与泛型编程

这是我们预期的结果。

类模板

下面是一个简单的数组类模板。

#include<iostream> #include <stdlib.h> using namespace std; template <class T>   class Array   {       public:           Array(int);           T & operator[] (int);           int getSize();           ~Array();       private:           T *a;           int size;           int errorValue;           Array();   };      template<class T>   Array<T> ::Array(int n)   {       a = new T[size = n];       errorValue = -1;   }      template<class T>   Array<T> ::~Array()   {       delete []a;  }   template<class T>   T& Array<T>::operator[](int index)   {       if(index < 0 || index >= size)       {           cout << "Out of boundry" << endl;           exit(1);     }       return a[index];   }      template<class T>   int Array<T>::getSize()   {       return size;   }    int main() {  	Array<double> a(10); 	Array<int> b(20); 	cout<<"a.size:"<<a.getSize()<<endl; 	for(int i=0;i<b.getSize();i++) 		cout<<b[i]<<endl; 	return 1; }

运行结果:

再学C++ Primer(11)-模板与泛型编程