现在的位置: 首页 > 综合 > 正文

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

2013年10月10日 ⁄ 综合 ⁄ 共 2630字 ⁄ 字号 评论关闭

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

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

模板是泛型编程的基础。

模板函数的例子

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

#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;
	call_with_max(++a,b+10);
	cout<<"a"<<a<<"b"<<b<<endl;
	cout<<"Hello"<<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;
}

运行结果:

抱歉!评论已关闭.