泛型编程与面向对象编程一样,都依赖于某种形式的多态性。面向对象编程所依赖的多态性称为运行时多态性,泛型编程所依赖的多态性称为编译时多态性或者参数式多态性。
在泛型编程中,我们所编写的类和函数都能多态地用于跨越编译时不相关的类型,一个类或者一个函数可以用来操纵多种类型的对象。标准库中的容器、迭代器和算法是很好的泛型编程的例子。
模板是泛型编程的基础。
模板函数的例子
首先来看一段用于比较大小的代码。
#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;
}
编译运行之后的结果如下:
上面的程序中,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;
}
运行结果:
这就是传说中的模板函数了,使用函数模板时,编译器会推断哪个模板实参绑定到模板形参。一旦编译器确定了实际的模板实参,就称它实例化了函数模板的一个实例。
编译器使用实参代替相应的模板形参并编译改版本的函数。
所以上面实际是编译了三个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;
}
运行后的结果会是这样:
第一次调用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;
}
运行结果:
这是我们预期的结果。
类模板
下面是一个简单的数组类模板。
#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;
}