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
26、b=A,C,E,F,D,B,U,V,W,Q;int i;cout*a数组*endl;cout排序前:endl;for(i=0;i10;i+)coutai ;coutendl;bubble_sort(a);cout排序后:endl;for(i=0;i10;i+)coutai ;coutendl;程序运行结果如下:程序运行结果如下:*a a数组数组*排序前:排序前:9 7 5 3 1 0 2 4 6 89 7 5 3 1 0 2 4 6 8排序后:排序后:0 1 2 3 4 5 6 7 8 90 1 2 3 4 5 6 7 8 9*b b数组数组*排序前:排序前:A C E F D B U V W
27、 QA C E F D B U V W Q排序后:排序后:A B C D E F Q U V WA B C D E F Q U V Wcout*b数组*endl;cout排序前:endl;for(i=0;i10;i+)coutbi ;coutendl;bubble_sort(b);cout排序后:endl;for(i=0;i10;i+)coutbi ;coutendl;return 0;8.2.3 模板参数 程序运行结果如下:程序运行结果如下:*a a数组数组*排序前:排序前:9 7 5 3 1 0 2 4 6 89 7 5 3 1 0 2 4 6 8排序后:排序后:0 1 2 3 4 5 6
28、 7 8 90 1 2 3 4 5 6 7 8 9*b b数组数组*排序前:排序前:A C E F D B U V W QA C E F D B U V W Q排序后:排序后:A B C D E F Q U V WA B C D E F Q U V Wv2.模板形参表模板形参表v本例中,本例中,size被声明为被声明为bubble_sort函数模板的非类型函数模板的非类型参数后,在模板定义的余下部分,它被当做一个常量参数后,在模板定义的余下部分,它被当做一个常量值使用。由于值使用。由于bubble_sort函数不是通过引用来传递函数不是通过引用来传递数组,故在模板调用时,必须显式指定模板实参,
29、明数组,故在模板调用时,必须显式指定模板实参,明确指定数组的大小。如果确指定数组的大小。如果bubble_sort函数是通过引函数是通过引用来传递数组,则在模板调用时,就可以不显式指定用来传递数组,则在模板调用时,就可以不显式指定模板实参,而由编译器自动推断出来,如下所示:模板实参,而由编译器自动推断出来,如下所示:8.2.3 模板参数 v2.模板形参表模板形参表vtemplate vvoid bubble_sort(T(&a)size)vmain()函数中的两个函数调用语句改为:函数中的两个函数调用语句改为:vbubble_sort(a);vbubble_sort(b);v不过,该程序用不过
30、,该程序用VC+6.0的的C+编译器不能编译通过,编译器不能编译通过,可改用其他编译器,如:可改用其他编译器,如:VC+7.0的的C+编译器、编译器、GNU C+编译器。编译器。8.2.3 模板参数 v2.模板形参表模板形参表v另外,本程序也可以不使用模板非类型参数来指定数另外,本程序也可以不使用模板非类型参数来指定数组的大小,而在组的大小,而在bubble_sort()函数的参数表中增加一函数的参数表中增加一个传递数组大小的个传递数组大小的int型参数。修改后的函数模板代码型参数。修改后的函数模板代码如下:如下:8.2.3 模板参数 v2.模板形参表模板形参表vtemplate vvoid
31、bubble_sort(T a,int n)v /此处代码与【例此处代码与【例8-4】中的相同,故省略不写】中的相同,故省略不写v for(i=n-1,change=true;i=1&change;-i)v /此处代码与【例此处代码与【例8-4】中的相同,故省略不写】中的相同,故省略不写vv同时,修改同时,修改main()函数中的两个函数调用语句为:函数中的两个函数调用语句为:vbubble_sort(a,10);vbubble_sort(b,10);8.2.3 模板参数 v2.模板形参表模板形参表v综上所述:函数模板形参表中可以出现用综上所述:函数模板形参表中可以出现用typename或或c
32、lass关键字声明的类型参数,还可以出现由普通参关键字声明的类型参数,还可以出现由普通参数声明构成的非类型参数。除此之外,函数模板形参数声明构成的非类型参数。除此之外,函数模板形参表中还可以出现类模板类型的参数,在模板调用时需表中还可以出现类模板类型的参数,在模板调用时需要为其提供一个类模板。要为其提供一个类模板。8.2.3 模板参数 v像普通函数一样,也可以用相同的函数名重载函数模板。像普通函数一样,也可以用相同的函数名重载函数模板。实际上,实际上,【例例8-2】中的中的max函数模板并不能完成两个函数模板并不能完成两个字符串数据的大小比较,如果在字符串数据的大小比较,如果在【例例8-2】中
33、的中的main函函数中添加如下语句:数中添加如下语句:vchar*s1=Beijing 2008,*s2=Welcome to Beijing;vcoutBeijing 2008,Welcome to Beijing两个字符两个字符串中的大者为:串中的大者为:max(s1,s2)y?x:y;v这里实际比较的不是两个字符串,而是两个字符串的这里实际比较的不是两个字符串,而是两个字符串的地址。那一个字符串的存储地址高,就输出那个字符地址。那一个字符串的存储地址高,就输出那个字符串。从输出结果看,应该是串。从输出结果看,应该是Beijing 2008的地址高。的地址高。为了验证这一点,我们用语句:为
34、了验证这一点,我们用语句:vcout&s1&s2endl;v输出输出s1和和s2的地址,结果为:的地址,结果为:v0012FF7C 0012FF788.2.4 函数模板重载v处理这种异常情况的方法可以有如下两种:处理这种异常情况的方法可以有如下两种:v(1)对函数模板进行重载,增加一个与函数模板同名)对函数模板进行重载,增加一个与函数模板同名的普通函数定义:的普通函数定义:vchar*max(char*x,char*y)v cout0?x:y;vv此外,还要在程序开头增加如下的此外,还要在程序开头增加如下的include命令:命令:v#include 8.2.4 函数模板重载v处理这种异常情况
35、的方法可以有如下两种:处理这种异常情况的方法可以有如下两种:v(2)改变函数调用)改变函数调用max(s1,s2)的实参类型为的实参类型为string,这样编译器就用这样编译器就用string实例化函数模板实例化函数模板T max(T x,T y),生成下面的模板函数:生成下面的模板函数:vstring max(string x,string y)v return xy?x:y;v此外,还要注意在程序开头增加如下的此外,还要注意在程序开头增加如下的include命令:命令:v#include 8.2.4 函数模板重载【例【例8-58-5】修改【例】修改【例8-28-2】的程序代码,使之也能完成
36、两个字】的程序代码,使之也能完成两个字符串数据的比较。符串数据的比较。#include#include using namespace std;template /声明函数模板T max(T x,T y)couty?x:y;8.2.4 函数模板重载char*max(char*x,char*y)/重载的普通函数 cout0?x:y;8.2.4 函数模板重载int main()char*s1=Beijing 2008,*s2=Welcome to Beijing!;coutmax(2,3)endl;coutmax(2.02,3.03)endl;coutmax(s1,s2)endl;/调用普通函数r
37、eturn 0;程序运行结果如下:程序运行结果如下:This is a template function!max is:3This is a template function!max is:3This is a template function!max is:3.03This is a template function!max is:3.03This is the overload function with charThis is the overload function with char*,char,char*!max is:Welcome to Beijing!max is:
38、Welcome to Beijing!【例【例8-68-6】阅读程序,写出程序的运行结果。】阅读程序,写出程序的运行结果。#include#include using namespace std;template /声明函数模板T max(T x,T y)couty?x:y;8.2.4 函数模板重载char*max(char*x,char*y)/重载的普通函数 cout0?x:y;int max(int x,int y)/重载的普通函数 couty?x:y;int max(int x,char y)/重载的普通函数 couty?x:y;8.2.4 函数模板重载int main()char*s1
39、=Beijing 2008,*s2=Welcome to Beijing!;coutmax(2,3)endl;/调用重载的普通函数coutmax(2.02,3.03)endl;/调用函数模板,此时T被double取代coutmax(s1,s2)endl;/调用重载的普通函数coutmax(2,a)endl;/调用重载的普通函数coutmax(2.3,a)endl;/调用重载的普通函数return 0;8.2.4 函数模板重载程序运行结果如下:程序运行结果如下:This is the overload function with int,int!max is:3This is the overl
40、oad function with int,int!max is:3This is a template function!max is:3.03This is a template function!max is:3.03This is the overload function with charThis is the overload function with char*,char,char*!max is:Welcome to Beijing!max is:Welcome to Beijing!This is the overload function with int,char!m
41、ax is:97This is the overload function with int,char!max is:97This is the overload function with int,char!max is:97This is the overload function with int,char!max is:97【例【例8-78-7】编写求】编写求2 2个数、个数、3 3个数和一组数中最大数的函数模板。个数和一组数中最大数的函数模板。#include#include using namespace std;template /声明函数模板T max(T x,T y)retu
42、rn xy?x:y;template /函数模板重载T max(T x,T y,T z)if(xy)x=y;if(xz)x=z;return x;8.2.4 函数模板重载template /函数模板重载T max(T a,int n)/求数组an中的最大数 T temp=a0;for(int i=1;in;i+)if(tempai)temp=ai;return temp;8.2.4 函数模板重载int main()string s1=Beijing 2008,s2=Welcome to Beijing!;int a=1,2,3,4,5,6,7,8,9;coutmax(2,3)endl;cout
43、max(2.02,3.03,4.04)endl;coutmax(s1,s2)endl;coutmax(a,9)endl;return 0;8.2.4 函数模板重载v运用函数模板可以设计出与具体数据类型无关运用函数模板可以设计出与具体数据类型无关的通用函数。与此类似,的通用函数。与此类似,C+也支持用类模板也支持用类模板来设计结构和成员函数完全相同,但所处理的来设计结构和成员函数完全相同,但所处理的数据类型不同的通用类。在设计类模板时,可数据类型不同的通用类。在设计类模板时,可以使其中的某些数据成员、成员函数的参数或以使其中的某些数据成员、成员函数的参数或返回值与具体类型无关。返回值与具体类型无
44、关。8.3 类模板v模板在模板在C+中更多的使用是在类的定义中,最中更多的使用是在类的定义中,最常见的就是常见的就是STL(Standard Template Library)和)和ATL(ActiveX Template Library),它们都是作为),它们都是作为ANSI C+标准集成标准集成在在VC+开发环境中的标准模板库。开发环境中的标准模板库。8.3 类模板v类模板的一般定义格式如下:类模板的一般定义格式如下:v templatev class 类名类名v v 类体类体v 8.3.1 类模板的定义【例例8-8】设计一个堆栈的类模板设计一个堆栈的类模板StackStack。/Stac
45、k.hconst int SSize=10;/SSize为栈的容量大小template /声明类模板,T为类型参数class Stackpublic:Stack()top=0;void push(T e);/入栈操作 T pop();/出栈操作 bool StackEmpty()return top=0;bool StackFull()return top=SSize;private:T dataSSize;/栈元素数组,固定大小为SSize int top;/栈顶指针;8.3.1 类模板的定义template /push成员函数的类外定义void Stack:push(T e)if(top=
46、SSize)coutStack is Full!Dont push data!endl;return;datatop+=e;8.3.1 类模板的定义template inline T Stack:pop()if(top=0)coutStack is Empty!Dont pop data!endl;return 0;top-;return datatop;8.3.1 类模板的定义v说明:说明:v(1)类模板中的成员函数既可以在类模板内定义,)类模板中的成员函数既可以在类模板内定义,也可以在类模板外定义。也可以在类模板外定义。v如果在类模板内定义成员函数,其定义方法与普通如果在类模板内定义成员函
47、数,其定义方法与普通类成员函数的定义方法相同,如类成员函数的定义方法相同,如Stack的构造函数、的构造函数、判断判断栈是否为空的栈是否为空的StackEmpty函数、判断栈是否已函数、判断栈是否已满的满的StackFull函数的定义。函数的定义。8.3.1 类模板的定义v说明:说明:v如果在类模板外定义成员函数,必须采用如下形式:如果在类模板外定义成员函数,必须采用如下形式:vtemplate v返回值类型返回值类型 类名类名:成员函数名成员函数名(参数列表参数列表)v ;v例如,上例例如,上例Stack的的push成员函数的定义:成员函数的定义:vtemplate /类模板声明类模板声明v
48、void Stack:push(T e)8.3.1 类模板的定义注意:在引用模板的类名的地方,注意:在引用模板的类名的地方,必须伴有该模板的参数名表。必须伴有该模板的参数名表。v说明:说明:v(2)如果要在)如果要在类模板外将成员函数定义为类模板外将成员函数定义为inline函数,函数,应该将应该将inline关键字加在类模板的声明后。例如,上关键字加在类模板的声明后。例如,上例例Stack的的push成员函数的定义:成员函数的定义:vtemplate /类模板声明类模板声明vinline T Stack:pop()/指定为内联函数指定为内联函数8.3.1 类模板的定义v说明:说明:v(3)类
49、模板的成员函数的定义必须同类模板的定义类模板的成员函数的定义必须同类模板的定义在同一个文件中。因为,类模板定义不同于类的定在同一个文件中。因为,类模板定义不同于类的定义,编译器无法通过一般的手段找到类模板成员函义,编译器无法通过一般的手段找到类模板成员函数的代码,只有将它和类模板定义放在一起,才能数的代码,只有将它和类模板定义放在一起,才能保证类模板正常使用。一般都放入一个保证类模板正常使用。一般都放入一个.h头文件中。头文件中。8.3.1 类模板的定义v在声明了一个类模板后,怎样使用它?在声明了一个类模板后,怎样使用它?vStack int_stack;v该语句用该语句用Stack类模板定义
50、了一个对象类模板定义了一个对象int_stack。编。编译器遇到该语句,会用译器遇到该语句,会用int去替换去替换Stack类模板中的所类模板中的所有类型参数有类型参数T,生成一个,生成一个int型的具体的类,一般称之型的具体的类,一般称之为模板类。该类的代码如下:为模板类。该类的代码如下:8.3.2 类模板的实例化class Stackpublic:Stack()top=0;void push(int e);/入栈操作int pop();/出栈操作bool StackEmpty()return top=0;/判断栈是否为空bool StackFull()return top=10;/判断栈是
侵权处理QQ:3464097650--上传资料QQ:3464097650
【声明】本站为“文档C2C交易模式”,即用户上传的文档直接卖给(下载)用户,本站只是网络空间服务平台,本站所有原创文档下载所得归上传人所有,如您发现上传作品侵犯了您的版权,请立刻联系我们并提供证据,我们将在3个工作日内予以改正。