《C++程序设计》课件第8章.ppt
- 【下载声明】
1. 本站全部试题类文档,若标题没写含答案,则无答案;标题注明含答案的文档,主观题也可能无答案。请谨慎下单,一旦售出,不予退换。
2. 本站全部PPT文档均不含视频和音频,PPT中出现的音频或视频标识(或文字)仅表示流程,实际无音频或视频文件。请谨慎下单,一旦售出,不予退换。
3. 本页资料《《C++程序设计》课件第8章.ppt》由用户(momomo)主动上传,其收益全归该用户。163文库仅提供信息存储空间,仅对该用户上传内容的表现方式做保护处理,对上传内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知163文库(点击联系客服),我们立即给予删除!
4. 请根据预览情况,自愿下载本文。本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
5. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007及以上版本和PDF阅读器,压缩文件请下载最新的WinRAR软件解压。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- C+程序设计 C+ 程序设计 课件
- 资源描述:
-
1、C+程序设计第第8 8章章 模板模板第第8章章 模板模板 本章学习要点本章学习要点函数模板类模板STL(Standard Template Library,标准模板库)本章学习目标本章学习目标了解函数模板的概念,掌握函数模板的定义与使用了解类模板的概念,掌握类模板的定义与使用了解STL有关内容。第第8章章 模板模板 v我们知道我们知道C+是一种强类型语言是一种强类型语言,强类型语,强类型语言所使用的数据都必须明确的声明为某种严言所使用的数据都必须明确的声明为某种严格定义的类型,并且在所有的数值传递中,格定义的类型,并且在所有的数值传递中,编译器都强制进行类型相容性检查。虽然强编译器都强制进行类
2、型相容性检查。虽然强类型语言有力地保证了语言的安全性和健壮类型语言有力地保证了语言的安全性和健壮性,但有时候,强类型语言对于实现相对简性,但有时候,强类型语言对于实现相对简单的函数似乎是个障碍单的函数似乎是个障碍。8.1 为什么需要模板【例例8-1】求两个数中的大者求两个数中的大者(分别考虑整数、长整数、实数的情况)。(分别考虑整数、长整数、实数的情况)。#include using namespace std;int max(int x,int y)/整数比较整数比较 return xy?x:y;/长整数比较长整数比较long max(long x,long y)return xy?x:y;
3、double max(double x,double y)/实数比较实数比较 return xy?x:y;8.1 为什么需要模板int main()int a=12,b=34,m;long c=67890,d=67899,n;double e=12.34,f=56.78,p;m=max(a,b);n=max(c,d);p=max(e,f);cout int_max=mendl;cout long_max=nendl;cout double_max=p(y)?(x):(y)v实际上,只是在预编译时把程序中每一个出实际上,只是在预编译时把程序中每一个出现现max(x,y)的地方,都使用预先定义好的
4、语的地方,都使用预先定义好的语句来替换它。这里就是用句来替换它。这里就是用(x)(y)?(x):(y)来来替换。替换。v该定义对于简单的该定义对于简单的max()函数调用都能正常函数调用都能正常工作,但是在稍微复杂的调用下,它就有可工作,但是在稍微复杂的调用下,它就有可能出现错误。能出现错误。8.1 为什么需要模板v例如,定义了如下的计算平方的带参数宏:例如,定义了如下的计算平方的带参数宏:v#define square(A)A*Av则如下的调用:则如下的调用:vsquare(a+2);v会被替换成会被替换成a+2*a+2,实际计算顺序变成了,实际计算顺序变成了a+(2*a)+2。v另外,宏定
5、义无法声明返回值的类型。如果宏另外,宏定义无法声明返回值的类型。如果宏运算的结果赋值给一个与之类型不匹配的变量,运算的结果赋值给一个与之类型不匹配的变量,编译器并不能够检查出错误。编译器并不能够检查出错误。8.1 为什么需要模板模板模板函数模板函数模板类模板类模板8.1 为什么需要模板v正因为使用宏在功能上的不便和不进行类型检正因为使用宏在功能上的不便和不进行类型检查的危险,查的危险,C+引入了模板的概念。引入了模板的概念。v所谓函数模板,实际上是建立一个通用函数,所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型中的全部或部分类型其函数类型和形参类型中的全部或部分类型不具体指定,用
6、一个虚拟的类型来代表。这不具体指定,用一个虚拟的类型来代表。这个通用函数就称为函数模板。凡是函数体相个通用函数就称为函数模板。凡是函数体相同的函数都可以用这个模板来代替,不必定同的函数都可以用这个模板来代替,不必定义多个函数,只需在模板中定义一次即可。义多个函数,只需在模板中定义一次即可。在函数调用时系统会根据实参的类型来取代在函数调用时系统会根据实参的类型来取代模板中的虚拟类型,从而实现了不同函数的模板中的虚拟类型,从而实现了不同函数的功能。功能。8.2 函数模板【例例8-2】将将【例例8-18-1】的程序改为通过函数模板实现。的程序改为通过函数模板实现。#include using nam
7、espace std;template T max(T x,T y)return xy?x:y;8.2.1 函数模板的定义int main()int a=12,b=34,m;long c=67890,d=67899,n;double e=12.34,f=56.78,p;m=max(a,b);/调用函数模板,此时T被int取代n=max(c,d);/调用函数模板,此时T被long取代p=max(e,f);/调用函数模板,此时T被double取代cout int_max=mendl;cout long_max=n endl;cout double_max=p endl;return 0;程序运行结
8、果如下:程序运行结果如下:int_max=34int_max=34long_max=67899long_max=67899double_max=56.78double_max=56.788.2.1 函数模板的定义v定义函数模板的一般形式为:定义函数模板的一般形式为:vtemplate 或或 template v返回类型返回类型 函数名函数名(形参表形参表)返回类型返回类型 函数名函数名(形参表形参表)v v 函数体函数体 函数体函数体v 8.2.1 函数模板的定义v说明:说明:v(1)在定义模板时,不允许)在定义模板时,不允许template语句与语句与函数模板之间有任何其他语句。下面的模板定
9、函数模板之间有任何其他语句。下面的模板定义是错误的:义是错误的:vtemplate vint a;/错误,不允许在此位置有任何语句错误,不允许在此位置有任何语句vT max(T x,T y)8.2.1 函数模板的定义v说明:说明:v(2)不要把这里的)不要把这里的class与类的声明关键字与类的声明关键字class混淆在一起,虽然它们由相同的字母组混淆在一起,虽然它们由相同的字母组成,但含义是不同的。为了区别类与模板参数成,但含义是不同的。为了区别类与模板参数中的类型关键字中的类型关键字class,标准,标准C+提出了用提出了用typename作为模板参数的类型关键字,同时作为模板参数的类型关
10、键字,同时也支持使用也支持使用class。如果用。如果用typename其含义就其含义就很清楚,肯定是类型名而不是类名。很清楚,肯定是类型名而不是类名。8.2.1 函数模板的定义v说明:说明:v(3)函数模板的类型参数可以不止一个,可)函数模板的类型参数可以不止一个,可根据实际需要确定个数,但每个类型参数都必根据实际需要确定个数,但每个类型参数都必须用关键字须用关键字typename或或class限定。限定。vtemplate vT1 fun(T1 a,T 2 b,T3 c)8.2.1 函数模板的定义v说明:说明:v(4)当一个名字被声明为模板参数之后,它)当一个名字被声明为模板参数之后,它就
11、可以使用了,一直到模板声明或定义结束为就可以使用了,一直到模板声明或定义结束为止。模板类型参数被用做一个类型指示符,可止。模板类型参数被用做一个类型指示符,可以出现在模板定义的余下部分。它的使用方式以出现在模板定义的余下部分。它的使用方式与内置或用户定义的类型完全一样,比如用来与内置或用户定义的类型完全一样,比如用来声明变量和强制类型转换。声明变量和强制类型转换。8.2.1 函数模板的定义v当编译器遇到关键字当编译器遇到关键字template和跟随其后的函数定义和跟随其后的函数定义时,它只是简单地知道:这个函数模板在后面的程序时,它只是简单地知道:这个函数模板在后面的程序代码中可能会用到。除此
12、之外,编译器不会做额外的代码中可能会用到。除此之外,编译器不会做额外的工作。在这个阶段,函数模板本身并不能使编译器产工作。在这个阶段,函数模板本身并不能使编译器产生任何代码,因为编译器此时并不知道函数模板要处生任何代码,因为编译器此时并不知道函数模板要处理的具体数据类型,根本无法生成任何函数代码。理的具体数据类型,根本无法生成任何函数代码。8.2.2 函数模板的实例化v当编译器遇到程序中对函数模板的调用时,它才会根当编译器遇到程序中对函数模板的调用时,它才会根据调用语句中实参的具体类型,确定模板参数的数据据调用语句中实参的具体类型,确定模板参数的数据类型,并用此类型替换函数模板中的模板参数,生
13、成类型,并用此类型替换函数模板中的模板参数,生成能够处理该类型的函数代码,即模板函数。能够处理该类型的函数代码,即模板函数。8.2.2 函数模板的实例化v函数模板与模板函数的关系如图函数模板与模板函数的关系如图8-1所示:所示:8.2.2 函数模板的实例化max函数模板template T max(T x,T y)return xy?x:y;max(a,b)生成的模板函数a,b为int类型int max(int x,int y)return xy?x:y;max(c,d)生成的模板函数c,d为long类型long max(long x,long y)return xy?x:y;max(e,f)
14、生成的模板函数e,f为double类型double max(double x,double y)return xy?x:y;实例化实例化实例化实例化v例如,在例如,在【例例8-2】的程序中,当编译器遇到的程序中,当编译器遇到vtemplate vT max(T x,T y)v时,并不会产生任何代码,但当它遇到函数调用时,并不会产生任何代码,但当它遇到函数调用max(a,b),编译器会将函数名,编译器会将函数名max与模板与模板max相匹配,相匹配,将实参的类型取代函数模板中的虚拟类型将实参的类型取代函数模板中的虚拟类型T,生成下,生成下面的模板函数:面的模板函数:vint max(int x,
15、int y)return xy?x:y;v然后调用它。然后调用它。8.2.2 函数模板的实例化v那么,是否每次调用函数模板时,编译器都会生成相那么,是否每次调用函数模板时,编译器都会生成相应的模板函数呢?假如在应的模板函数呢?假如在【例例8-2】中有下面的函数中有下面的函数调用:调用:vint u=max(1,2);vint v=max(3,4);vint w=max(5,6);v编译器是否会实例化生成编译器是否会实例化生成3个相同的个相同的max(int,int)模板模板函数呢?函数呢?8.2.2 函数模板的实例化v答案是否定的。编译器只在第答案是否定的。编译器只在第1次调用时生成模板函次调
16、用时生成模板函数,当之后遇到相同类型的参数调用时,不再生成其数,当之后遇到相同类型的参数调用时,不再生成其他模板函数,它将调用第他模板函数,它将调用第1次实例化生成的模板函数。次实例化生成的模板函数。v可以看出,用函数模板比用函数重载更方便,程序更可以看出,用函数模板比用函数重载更方便,程序更简洁。但它只适用于函数的参数个数相同而类型不同,简洁。但它只适用于函数的参数个数相同而类型不同,且函数体相同的情况,如果参数的个数不同,则不能且函数体相同的情况,如果参数的个数不同,则不能用函数模板。用函数模板。8.2.2 函数模板的实例化v1.模板参数的匹配问题模板参数的匹配问题vC+在实例化函数模板的
17、过程中,只是简单地将模板在实例化函数模板的过程中,只是简单地将模板参数替换成调用实参的类型,并以此生成模板函数,参数替换成调用实参的类型,并以此生成模板函数,不会进行参数类型的任何转换。这种方式与普通函数不会进行参数类型的任何转换。这种方式与普通函数的参数处理有着极大的区别,在普通函数的调用过程的参数处理有着极大的区别,在普通函数的调用过程中,中,C+会对类型不匹配的参数进行隐式的类型转换。会对类型不匹配的参数进行隐式的类型转换。8.2.3 模板参数 v1.模板参数的匹配问题模板参数的匹配问题v例如,在【例例如,在【例8-2】的】的main()函数中再添加如下语句:函数中再添加如下语句:vco
18、ut2,2.3两数中的大者为:两数中的大者为:max(2,2.3)endl;vcout a,2两数中的大者为:两数中的大者为:max(a,2)endl;v编译程序,将会产生编译程序,将会产生2个编译错误:个编译错误:verror C2782:T _cdecl max(T,T):template parameter T is ambiguousvcould be double or intverror C2782:T _cdecl max(T,T):template parameter T is ambiguousvcould be int or charv1.模板参数的匹配问题模板参数的匹配问
19、题v这种问题的解决方法有以下几种:这种问题的解决方法有以下几种:v(1)在模板调用时进行参数类型的强制转换,如下)在模板调用时进行参数类型的强制转换,如下所示:所示:vcout2,2.3两数中的大者为:两数中的大者为:max(double(2),2.3)endl;vcout a,2 两数中的大者为:两数中的大者为:max(int(a),2)endl;8.2.3 模板参数 v1.模板参数的匹配问题模板参数的匹配问题v这种问题的解决方法有以下几种:这种问题的解决方法有以下几种:v(2)通过提供)通过提供里面的参数类型来调用这个模板,里面的参数类型来调用这个模板,如下所示:如下所示:vcout2,2
20、.3两数中的大者为:两数中的大者为:max(2,2.3)endl;vcout a,2 两数中的大者为:两数中的大者为:max(a,2)endl;8.2.3 模板参数 v1.模板参数的匹配问题模板参数的匹配问题v这种问题的解决方法有以下几种:这种问题的解决方法有以下几种:v(3)指定多个模板参数)指定多个模板参数v对于【例对于【例8-2】的】的max函数模板来说,我们可以为它指函数模板来说,我们可以为它指定两个不同的类型参数。定两个不同的类型参数。8.2.3 模板参数【例【例8-38-3】将【例】将【例8-28-2】的】的maxmax函数模板参数由一个改为两个。函数模板参数由一个改为两个。#in
21、clude using namespace std;template T1 max(T1 x,T2 y)return xy?x:y;int main()cout2,2.3两数中的大者为:max(2,2.3)endl;cout a,2 两数中的大者为:max(a,2)endl;return 0;8.2.3 模板参数 程序运行结果如下:程序运行结果如下:2,2.32,2.3两数中的大者为:两数中的大者为:2 2a,2 2两数中的大者为:两数中的大者为:a av1.模板参数的匹配问题模板参数的匹配问题v编译该程序,将不再会产生编译错误。但函数的运行编译该程序,将不再会产生编译错误。但函数的运行结果并
22、不精确,甚至存在较大的误差,但它并不表示结果并不精确,甚至存在较大的误差,但它并不表示程序有什么错误。其原因是:程序有什么错误。其原因是:max函数模板的返回值函数模板的返回值类型依赖于模板参数类型依赖于模板参数T1。如果在调用时将精度高的数。如果在调用时将精度高的数据类型作为第一个参数,结果将是正确的。上述语句据类型作为第一个参数,结果将是正确的。上述语句如果改写成如下形式:如果改写成如下形式:v cout2,2.3两数中的大者为:两数中的大者为:max(2.3,2)endl;v cout a,2 两数中的大者为:两数中的大者为:max(2,a)endl;8.2.3 模板参数 v2.模板形参
23、表模板形参表v函数模板形参表中除了可以出现用函数模板形参表中除了可以出现用typename或或class关键字声明的类型参数外,还可以出现确定类型参数,关键字声明的类型参数外,还可以出现确定类型参数,称为非类型参数。例如:称为非类型参数。例如:vtemplate vT1 fun(T1 a,T 2 b,T3 c)v 8.2.3 模板参数 v2.模板形参表模板形参表v模板非类型参数名代表了一个潜在的值。它被用做一模板非类型参数名代表了一个潜在的值。它被用做一个常量值,可以出现在模板定义的余下部分。它可以个常量值,可以出现在模板定义的余下部分。它可以用在要求常量的地方,或是在数组声明中指定数组的用在
24、要求常量的地方,或是在数组声明中指定数组的大小或作为枚举常量的初始值。在模板调用时只能为大小或作为枚举常量的初始值。在模板调用时只能为其提供相应类型的常数值。非类型参数是受限制的,其提供相应类型的常数值。非类型参数是受限制的,通常可以是整型、枚举型、对象或函数的引用,以及通常可以是整型、枚举型、对象或函数的引用,以及对象、函数或类成员的指针,但不允许用浮点型(或对象、函数或类成员的指针,但不允许用浮点型(或双精度型)、类对象或双精度型)、类对象或void作为非类型参数。作为非类型参数。8.2.3 模板参数 v2.模板形参表模板形参表v【例【例8-4】用函数模板实现数组的冒泡排序,数组可以】用函
25、数模板实现数组的冒泡排序,数组可以是任意类型,数组的大小由模板参数指定。是任意类型,数组的大小由模板参数指定。8.2.3 模板参数#include using namespace std;template void bubble_sort(T asize)int i,j;bool change;for(i=size-1,change=true;i=1&change;-i)change=false;for(j=0;jaj+1)T temp;temp=aj;aj=aj+1;aj+1=temp;change=true;int main()int a=9,7,5,3,1,0,2,4,6,8;char
展开阅读全文