零点起飞学C++之模板_第1页
零点起飞学C++之模板_第2页
零点起飞学C++之模板_第3页
零点起飞学C++之模板_第4页
零点起飞学C++之模板_第5页
已阅读5页,还剩33页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、第17章 模 板模板(Template)是根据参数类型生成函数和类的机制。通过使用模板,可以只设计一个类来处理多种类型的数据,而不必为每一种类型分别创建类。这样就可以写出更简捷,更具效率,更智能的软件。本章读者将可以不需要再重复设计大段的代码,而是设计某种模式,掌握更高技巧的设计方法。17.1 什么是模板模板是一种参数化(parameterized)的通用类或通用函数。从软件工程的角度来讲,模板是一种重要的软件复用技术。C+程序都是由类和函数组成的,所以模板可以分为类模板和函数模板。下面从一个简单的模板开始,对模板的定义、模板的使用等做个初步的介绍。例如,编写一个函数比较两个变量的大小,并返回

2、其中较大者。如果不使用模板,则必须为每种类型都写一个函数。【示例17-1】 多个数据类型的比较函数。int getmax(int x, int y)/整型数的比较return (xy?x:y);float getmax(float x, float y)/浮点数的比较return (xy?x:y);char getmax(char x, char y)/字符的比较return (xy?x:y);分析:该示例定义了三个函数,分别用于比较整型数、浮点数和字符型。这利用了重载技术,但如果还需要比较其他数据类型,就必须为它也重载一个函数。如果利用模板技术,就可以只定义一个函数。【示例17-2】 用模板

3、技术重写getmax()函数。分析:在第一行语句声明中,用关键字template生成了一个通用数据类型的模板,叫做mytype。因此在其后面的函数中,mytype就成为一个有效的数据类型。它被用来定义了两个参数x和y,并用做函数getmax()的返回值类型。但是mytype并不代表任何具体的数据类型,而是直到被调用时,才由参数的类型来决定。因此,在写getmax()函数时就不需要考虑参数的类型,而是只考虑实现的代码。17.2 类 模 板类模板(Class Templates)指类的模板,它定义了一个具有同样的代码实现,但却具有不同类型的类簇。类模板定义了一个通用数据类型,并用来修饰属性成员、成

4、员函数的参数和返回值等需要类型说明的地方。17.2.1 定义类模板类模板的一般定义形式如下所示。template class ClassName/类声明体template 返回类型ClassName :MemberFunction1(形式参数表)/成员函数1函数体说明:可以包含基本数据类型,也可以包含类类型。后面的成员函数定义中,ClassName 中的“类型名表”是类型形式参数。这种类模板的定义其实只是对类的描述,不是具体的类。建立类模板后,可以通过创建类模板的实例来使用该类模板。创建类模板实例的方式如下:ClassName objectName;其中,ClassName是定义类模板时定义的

5、类名,是定义类时用到的类型。17.2.2 使用类模板在17.2.1节,学习了类模板的定义,本节将列举一些具体的类模板定义及使用实例。【示例17-3】 定义类模板Temp,并用来存储两个任意类型的元素。template /定义模板Tclass Temp private:T values2;/用模板T声明数组public:Temp (T x, T y) /用模板T修饰函数的参数values0 = x;values1 = y;分析:在示例中,定义了一个简单的模板类Temp,用来存储两个任意数据类型的元素。其中,T是模板类中没有具体定义的类型,该类型直到引用时才会具体定义。因此,如果用来存储两个整型数

6、据10 和20,则需要按如下方式调用:Temp intTemp (10, 20);同样,若用来存储两个浮点型数据25.5 和36.8,可以写成:Temp floatTemp(25.5, 36.8);【示例17-4】 一个较为复杂的类模板,该类模板实现了对数组的排序、查找和求和。分析:示例中设计了一个类模板templateclass Array,用于对T类型的数组进行排序、查找元素和求元素和,然后由此产生模板类Array和Array。在类模板定义中,可允许多个参数,也可以为模板参数设置默认值,就像为函数参数设置默认值一样。如在模板参数中用参数array1_size和array2_size来指定数

7、组的维数,并分别指定了参数的默认值10和5。【示例17-5】 带初始值的模板定义。template class Array/类声明体;分析:此处的array1_size和array2_size的值,并不会存放在类中。但对它们的使用,就如同是成员函数中的数据成员。17.2.3 类模板VS模板类类模板是模板的定义,不是一个实在的类,它是定义中用到通用类型参数。模板类是实在的类定义,是类模板的实例化。类定义中的参数在实例化时,才被实际类型所代替。【示例17-6】 定义类模板Array,然后对其进行实例化。template class Array/类声明体;Array array1(10); 分析:A

8、rray就是一个类模板, 是对类的抽象,代表一类具有相同实现方式或功能的类。Array则是模板类,是类模板的实例,代表一个具体的类。17.3 函 数 模 板函数模板(Function Templates)定义了一个函数簇。该簇中的所有函数都具有相同的代码实现,但却具有不同的数据类型。具体来讲,就是参数的类型、返回值类型或函数体中使用的类型都是通用类型的函数,就称为函数模板。17.3.1 定义函数模板函数模板的一般定义形式如下所示。template 返回类型 FunctionName(形式参数表)/函数体说明: 可以包含基本数据类型。函数模板定义不是一个实实在在的函数,编译系统不为其产生任何执行

9、代码。该定义只是对函数的描述,表示它每次能单独处理在类型形式参数表中说明的数据类型。当编译系统发现有一个函数调用FunctionName(实在参数表)时,将根据实在参数表中的类型,确认是否匹配函数模板中对应的形式参数表,然后生成一个重载函数。该重载函数的定义和函数模板的函数定义相同,但形式参数表的类型则以实在参数表的实际类型为依据。该重载函数就称为模板函数。17.3.2 使用函数模板在本章开篇时,引入的两个数比较求最大值getmax的简单模板,实际上就是一个函数模板。可以使用函数模板的例子很多,如求绝对值的函数、求最大值的函数、排序的函数等。它们都可以针对不同数据类型的数据,对应出同名的多个函

10、数的重载。为了实现这些同名的重载函数的功能,可以定义成一个以参加操作的数据类型为模板参数的函数模板。【示例17-7】 定义一个函数模板sum,求出array数组的元素之和并返回。分析:该示例定义了一个模板函数,该函数实现数组的求和功能。调用时,分别使用整型和浮点型两种数据。与类模板定义一样,函数模板也可允许多个参数,并可以为模板参数设置默认值。但要注意,在函数模板中使用多个类型参数时,一定要避免类型参数的二义性。【示例17-8】 以求两个数的最大值的函数模板getmax为例,下述代码将产生二义性。分析:该示例中,在语句行getmax(205.5, 300);将会出现参数的二义性错误。因为两个参

11、数的类型不一致,所以无法判断使用什么样的参数类型来替换模板。为此,C+提供了另一种完整调用模板的方法,如下所示。function name (parameters);使用这种格式,示例17-8中的“getmax(205.5, 300);”可以写成“getmax(205.5, 300);”,这种调用方式显式地指明用double来替换模板T。因此就避免了参数传递的二义性。此外,还可以通过在模板中声明多个类型参数来避免二义性。【示例17-9】 给出另一种避免二义性的方法。template T1 getmax (T1 x, T2 y) if(xy)return x;elsereturn y;分析:该模

12、板有两个类型参数,分别是T1和T2。在调用时,这两个参数类型将分别被替换,不会互相干扰。因此,“getmax(205.5, 300);”就可以写成“getmax(205.5, 300);”,这就不会出现二义性的错误。注意:一般来说,只有在编译器可以推断出模板参数类型时,模板参数才可以省略。17.3.3 函数模板VS模板函数函数模板是模板的定义,定义中用到通用类型参数。模板函数是实实在在的函数定义,它由编译系统在碰到具体的函数调用时所生成,拥有程序代码,将函数模板实例化就得到了模板函数。因此,函数模板是一个抽象的定义,而模板函数则是一个实在的实体。例如在示例17-8中,T getmax (T x

13、, T y)是一个函数模板,是对函数的抽象。而“getmax(205.5, 300);”则是模板函数,是一个实际可以调用的函数。17.4 模板的实例化模板实例化指采用特定模板,给出其具体的类型参数的组合,从而特化一个具体的类或函数的过程。下面分别详细讲解函数模板和类模板实例化的过程。1函数模板的实例化函数模板的实例化就是编译器根据函数模板生成具体的函数定义的过程。其特性如下:用实际参数的类型替换函数模板定义中的模板参数;每个实例都是一个完整的函数定义。【示例17-10】 示例17-9中的函数模板“T1 getmax(T1 x, T2 y)”的实例化。getmax(205.5, 300);/参数

14、为double和int型getmax(205, 300);/参数为int和int型getmax(a, b);/参数为char型分析:该示例实例化了示例17-9中的函数模板。可以看出,实例化的过程就是用具体的类型代替了模板中的类型参数。编译器直到在编译时,才能根据具体的参数为模板实例化一个完整的函数定义。如果不使用模板,那么示例中的三个函数就只能通过重载来分别实现。2类模板的实例化类模板的实例化是指编译器根据类模板生成具体的类的过程。其特性如下:通过用实际参数的类型替换类模板定义中的模板参数;每个实例都是一个具体类。【示例17-11】 示例17-6中定义的类模板Array的实例化。Array a

15、int;Array afloat;Array achar;分析:该示例是对模板Array的三个实例化。在编译时,编译器将根据类型参数生成具体的类。语句Array aint指示编译器用模板Array定义一个类,该类中的数据将以int为类型。这种实现时的指示说明使得可以用一个类模板生成许多不同的类实体。因此语句Array afloat将指示编译器生成另一个类,该类的数据为float型。3模板的强制实例化所谓模板的强制实例化,指在实例化时不给出明确的模板参数类型,而是完全依靠编译器对实际参数的类型判断来决定。这样做的结果是很容易引起二义性,正如在示例17-8中所演示的那样。所以,一般建议在实例化时明

16、确指出参数的类型。17.5 模板的作用模板是泛型编程的基础,所谓泛型编程就是用独立与任何特定类型的方式编写代码。模板的作用不仅仅在于此。借助于模板,用户还可开发出具有健壮性、通用性和高性能的类库。关于模板的内容,需要了解的还有很多,它们构成了C+语言内的一个子语言,使得程序员能在更大程度上控制编译过程。17.6 基于模板的元编程模板元编程是一种利用模板在编译期间执行指定程序的技术。模板引入C+不是为了元编程,而是为了定义通用类型或函数。但是自从模板元编程被发现以来,迅速变成一种非常流行而高效的编程手段。例如Blitz+、loki、boost、STL等,都提供了强大的解决方案,有的甚至已经进入C

17、+标准的一部分。本节将向读者初步介绍元编程的思想,展现它的魅力之处。说明:这里说模板元编程是被“发现”,而不是“发明”。因为这种技术不是新的,而是模板技术的一种精巧而意想不到的使用方式。17.6.1 什么是元编程元编程(Metaprogramming),更准确地说也就是“编写可以编程序的程序”。也就是说,给出代码的产生规则,编译器在编译期(Compile-time)解释这些规则并生成新代码来实现预期的功能。元编程在1994年初露端倪,由一个叫Erwin Unruh的人首先发现。在1994年,C+标准委员会在圣迭哥举行的一次会议期间,Erwin Unruh展示了一段特别的代码。这段代码的特别之处

18、在于程序的功能在编译期实现而非运行期,编译器以错误信息的方式产生从2到某个给定值之间的所有质数。同年夏天,Todd Veldhuizen受Erwin的例子启发,发现可以使用C+模板进行元编程,并发表了一份技术报告。次年5月,他又在C+ Report上发表了一篇名为Using C+ template metaprograms的文章,从而将编译期模板编程(Compile-time Template Programming)升华为C+模板元编程(Template Metaprogramming,TMP)。17.6.2 基于模板的元编程基于模板的元编程是写Template-based(基于模板)的运行于编译期间的C+程序的过程。模板元程序(Template Metaprogram)则表示“可以编程序的程序”。利用模板元编程,可以实现用其他方法很难或不能完成的一些任务;也可以将工作转移到编译期间,使得通常在运行时才能发现的错误在编译期间就被发现;因此,就可以编写出更高效、更短的代码,缩短了运行时间。【示例17-12】 计算Fibonacci数列第N项Fibonacci数的代码,其中使用了元编程的思想。分析:该示例定义了一个类模板,类中声明了一个枚举类型,该程序的奥秘就在于枚举类型的构造上。从枚举类型的构造可以看出,它自身有一个隐含的迭代计算。两个构造函数为枚举型初

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论