模板和泛型编程

来源:互联网 发布:mac虚拟机驱动 编辑:程序博客网 时间:2024/06/05 04:45

        在创建完成抽象操作的函数时,如:拷贝,反转和排序,你必须定义多个版本以便能处理每一种数据类型。以比较两个数的大小为例:

#include<iostream>using namespace std;int MAX(int a, int b){return a > b ? a:b;}double MAX(double a, double b){return a > b ? a : b;}int main(){cout<<"较大的是:"<<MAX(1, 2)<<endl;cout << "较大的是:" << MAX(1.1, 2.1) << endl;system("pause");return 0;}

通过这个函数可以发现:(1)只要输入的数据类型改变,就要添加相应的函数类型;

                                            (2)除了类型不同以外,函数代码均相同,代码复用率低;

                                            (3)一个出现问题,所有的函数都有问题,不好维护;

那么有没有更好的方法解决这个问题呢?当然有啦,运用泛型编程就可以很好地解决它。

泛型编程:编写与类型无关的逻辑代码,是代码复用的一种重要手段。

模板是实现它的重要基础。

模板函数:函数模板的数据类型参数标识符实际上是一个类型形参,在使用函数模板时,要将这个形参实例化为确定的数据类型。将类型形参实例化的参数称为模板实参,用模板实参实例化的函数称为模板函数。模板函数的生成就是将函数模板的类型形参实例化的过程。

定义格式 函数模板允许使用多个类型参数,但在template定义部分的每个形参前必须有关键字typename或class,即:

template<class 数据类型参数标识符1,…,class 数据类型参数标识符n>

<返回类型><函数名>(参数表)

{

     函数体

}

例如:

template<class T>T MAX(T a, T b){return a > b ? a : b;}int main(){cout<<"较大的是:"<<MAX(1, 2)<<endl;cout << "较大的是:" << MAX(1.1, 2.1) << endl;cout << "较大的是:" << MAX('A', 'B') << endl;system("pause");return 0;}


通过模板来实现,就比较简单了,做一简单的分析,如下图

那么模板函数的编译过程是怎样的呢?

在编译的时候:

1)实例化前,先检查模板代码本身,查看语法错误等,如遗漏分号等;

2)在实例化期间,检查模板代码,查看是不是所有的调用都有效。如该实例化类型不支持某些函数的调用。

 模板形参数:分为模板类型参数、非类型参数

(1)类型参数:类型形参由关见字class或typename后接说明符构成,如template<class T> void h(T a){};其中T就是一个类型形参,类型形参的名字由用户自已确定。模板形参表示的是一个未知的类型。模板类型形参可作为类型说明符用在模板中的任何地方,与内置类型说明符或类类型说明符的使用方式完全相同,即可以用于指定返回类型,变量声明等

(2)非类型参数模板的非类型形参也就是内置类型形参,如template<class T, int a> class B{};其中int a就是非类型的模板形参。

要注意的是:

 a非类型模板的形参只能是整型,指针和引用,像double,String, String **这样的类型是不允许的。但是double &,double *,对象的引用或指针是正确的。

 b调用非类型模板形参的实参必须是一个常量表达式,即他必须能在编译时计算出结果。

template<class T>const T& MAX(const T& a, const T& b){   return a>b ? a : b;}int main(){cout<<"较大的是:"<<MAX(1, 2)<<endl;cout << "较大的是:" << MAX(1.1, 2.1) << endl;cout << "较大的是:" << MAX('A', 'B') << endl;system("pause");return 0;}

模板实例化:有显示和隐式两种

显示实例化:

template<class T>const T& MAX(const T& a, const T& b){   return a>b ? a : b;}int main(){cout<<"较大的是:"<<MAX(1, 2)<<endl;cout << "较大的是:" <<MAX<int>(1, 2.1) << endl;//显示实例化cout << "较大的是:" << MAX('A', 'B') << endl;system("pause");return 0;
}
MAX(1,2.1)实例化中的两个数据的类型不同,第一个数据是int型,第二个数据是double型,直接调用,模板不能根据需要生成相应的函数

所以通过实例化MAX<int>(1,2.1>将double类型的数据转换成int型,就可以成功运行了。

隐式实例化:就是根据实例化的实参类型生成相应的类型函数,并调用过程,它的一般适用于参数列表实参类型都相同的数据

函数模板特化:当函数模板需要对某些类型进行特别处理,称为函数模板的特化


输出的结果是0,与原来比较两个字符串是否相等的结果不一致;对于传入的是char*类型的,而模板只是简单的简单的比较了传入参数的值,即两个指针是否相等,因此这里打印0。显然,这与我们的初衷不符,所以就需要对其进行实例化。

对模板函数进行特化如下:

template <>  bool IsEqual<const char*>(const char* t1, const char* t2)           //函数模板特化  {       return strcmp(t1, t2);  }

模板函数特化形式如下:

1、关键字template后面接一对空的尖括号<>
2、函数名后接模板名和一对尖括号,尖括号中指定这个特化定义的模板形参
3、函数形参表
4、函数体
template<>
返回值 函数名<Type>(参数列表)
{
// 函数体
}


原创粉丝点击