《C铁道出版社第2版第八章》由会员分享,可在线阅读,更多相关《C铁道出版社第2版第八章(26页珍藏版)》请在金锄头文库上搜索。
1、C+铁道出版社第铁道出版社第2版版第八章第八章8/5/20242第4章 串 8.1 模板的概念 定义求最大值函数max(): int max(int x,int y) return (xy)?xy; float max(float x,float y) return (xy)?xy; double max(double x,double y) return (xy)?xy; 这些函数的功能都是相这些函数的功能都是相同的,只是同的,只是参数类型参数类型和函和函数数返回类型返回类型不同不同 问题:能否问题:能否将这些函数合将这些函数合起来,只写起来,只写一一个个通用函数通用函数呢呢?8/5/202
2、43第4章 串 解决这个问题的方法: 使用模板 模板是实现代码重用机制的一种工具, 它把类型定义为参数,实现类型参数化。 调用时,T 可以分别取为int 、float 、double 把把类型类型定义为参数,如下所示:定义为参数,如下所示: T T max( max(T T x x,T T y) y) return (xy) return (xy)?xyxy; 类型参数类型参数8/5/20244第4章 串 int max(int x,int y) return (xy)?xy; float max(float x,float y) return (xy)?xy; double max(doub
3、le x,double y) return (xy)?xy; 把类型定义为参数,如下所示: T max(T x,T y) return (xy)?xy; 类型参数类型参数调用时调用时, ,T T取取intint调用时调用时, ,T T取取floatfloat调用时调用时, ,T T取取doubledouble 8/5/20245第4章 串 函数模板 模板 类 模 板 8/5/20246第4章 串 8.2.1 函数模板的声明 函数模板可声明如下: 函数模板也可以定义成如下形式: templatetemplate 返回类型返回类型 函数名函数名( (模板形参表模板形参表) ) 函数体函数体 使用函
4、数模板时使用函数模板时, , 类型参数类型参数必须实例化必须实例化, ,即用即用实际的数据类型实际的数据类型替代它。替代它。 templatetemplate是一是一个声明模板的关键个声明模板的关键字,它表示声明一字,它表示声明一个模板。个模板。 templatetemplate 返回类型返回类型 函数名函数名( (模板形参表模板形参表) ) 函数体函数体 8/5/20247第4章 串例如,求最大值函数模板,如下所示: template T max(T x,T y) return (xy)?xy;也可以定义成如下形式: template T max(T x,T y) return (xy)?x
5、y; T T为类型参数为类型参数 模板形参表模板形参表 8/5/20248第4章 串8.2.2 函数模板的使用 函数模板代表的是一类函数,使用时,类型参数必须实例化,即用实际的数据类型(既可以是系统预定义的标准数据类型(int 、float 、double等), 也可以是用户自定义的类型)替代它。 将函数模板中的类型参数实例化的参数称为模板实参。 用模板实参实例化的函数称为模板函数。 当编译系统发现有一个函数调用: 函数名(模板实参表);时,将根据模板实参表中的类型生成一个函数即模板函数。该模板函数的函数体与函数模板的函数体相同。8/5/20249第4章 串/例例8.1-18.1-1#incl
6、ude#includeusing namespace std;using namespace std;template template T T max( max(T T x,x,T T y) y) return (xy) ? x:y; return (xy) ? x:y;main( )main( ) int int i1=10, i2=56; i1=10, i2=56; floatfloat f1=12.5, f2=24.5; f1=12.5, f2=24.5; double double d1=50.344, d2=4656.346;d1=50.344, d2=4656.346; char
7、char c1=k,c2=n; c1=k,c2=n; coutthe max of i1,i2 is: coutthe max of i1,i2 is:max(i1,i2)max(i1,i2)endl;endl; coutthe max of f1,f2 is: coutthe max of f1,f2 is:max(f1,f2)max(f1,f2)endl;endl; coutthe max of d1,d2 is: coutthe max of d1,d2 is:max(d1,d2)max(d1,d2)endl;endl; coutthe max of c1,c2 is: coutthe
8、max of c1,c2 is:max(c1,c2)max(c1,c2)endl;endl; return 0; return 0;函数模板函数模板 程序运行结果如下:程序运行结果如下:the max of i1,i2 is:56the max of i1,i2 is:56the max of f1,f2 is:24.5the max of f1,f2 is:24.5the max of d1,d2 is:4656.35the max of d1,d2 is:4656.35the max of c1,c2 is:nthe max of c1,c2 is:n 类型参数类型参数T T 将将分别被类
9、型分别被类型int int 、floatfloat 、doubledouble、charchar等取代等取代。8/5/202410第4章 串 可见:所谓函数模板,实际上是建立一个通用函数,其函数返回类型和形参类型不具体指定,用一个虚拟的类型来代表。函数模板经实例化而生成的具体函数称为模板函数。 函数模板代表了一类函数, 模板函数表示某一具体的函数。8/5/202411第4章 串说明:(1) 在函数模板中允许使用多个类型参数。但是应当注意template定义部分的每个类型参数前必须有关键字typename (或class )。例例8.3-1 8.3-1 建立了有两个类型参数的函数模板。建立了有两
10、个类型参数的函数模板。#include #include using namespace std;using namespace std;template typename template void myfunc( type1 x, type2 y)void myfunc( type1 x, type2 y) coutx yendl; coutx yendl;main()main() myfunc(10, hao); myfunc(10, hao); myfunc(0.123, 10L); myfunc(0.123, 10L); return 0; return 0;两两个个类类型型参参数数
11、type1type1和和type2type2 运行结果为:运行结果为: 10 hao 10 hao 0.123 10 0.123 108/5/202412第4章 串 (2) 在template语句与函数模板定义语句之间不允许有别的语句。 例如下面的程序段就不能编译。 template int i; /错误 T max( T x,T y ) return ( xy)?xy; (3) 模板函数类似于普通重载函数,但更严格一些。 普通的非模板函数被重载的时候,在每个函数体内可以执行不同的动作。 但同一函数模板实例化后的所有模板函数都必须执行相同的动作。8/5/202413第4章 串 (3) (3)
12、模板函数类似于普通重载函数,但更严格一些。模板函数类似于普通重载函数,但更严格一些。 普通的非模板函数被重载的时候,在每个函数体内可以执行不同的动作。 但同一函数模板实例化后的所有模板函数都必须执行相同的动作。 例如,下面的重载函数就不能用模板函数代替: 函数1: void outdate(int i) couti; 函数2: void outdata(double d) coutd=dendl; 因为它们所执行的动作是不同的。8/5/202414第4章 串 (4) (4) 同一般函数一样,函数模板也可以重载。同一般函数一样,函数模板也可以重载。#include /#include /例例8.
13、4-18.4-1templatetemplateType max(Type x,Type y)Type max(Type x,Type y) return (xy)?x:y; return (xy)?x:y;template template Type max(Type x,Type y,Type z)Type max(Type x,Type y,Type z) Type t; Type t; t=(xy)? x:y; t=(xy)? x:y; return(tz)?t:z; return(tz)?t:z; main( )main( ) int m=10, n=20, max2; int m=
14、10, n=20, max2; float a=10.1, b=20.2, c=30.3, max3; float a=10.1, b=20.2, c=30.3, max3; max2=max(m,n);max2=max(m,n); max3=max(a,b,c);max3=max(a,b,c); coutmax(m,n)=max2endl; coutmax(m,n)=max2endl; coutmax(a,b,c)=max3endl; coutmax(a,b,c)=max3endl; return 0; return 0; 函数模板重载函数模板重载运行结果运行结果: :max(10,20)=
15、20max(10,20)=20max(10.1,20.2,30.3)=30.3max(10.1,20.2,30.3)=30.38/5/202415第4章 串 (5) 函数模板与同名的非模板函数可以重载。在这种情况下,调用的顺序是: 首先寻找一个参数完全匹配的非模板函数,如果找到了就调用它; 若没有找到,则寻找函数模板,将其实例化,产生一个匹配的模板函数,若找到了,就调用它。8/5/202416第4章 串#include /例例8.5-1 函数模板与非模板函数重载举例。函数模板与非模板函数重载举例。using namespace std;template /模板声明模板声明, ,其中其中ATAT
16、为类型参数为类型参数AT max(AT x,AT y) /定义函数模板定义函数模板 couty)? x:y; int max(int x,int y) /定义定义非模板函数非模板函数max,max,与函数模板与函数模板maxmax重载重载 couty) ? x:y; int main() int i1=10, i2=56; double d1=50.34, d2=4656.34; char c1=k,c2=n; cout较大的整数是较大的整数是:max(i1,i2)endl; cout较大的双精度型数是较大的双精度型数是:max(d1,d2)endl; cout较大的字符串是较大的字符串是:m
17、ax(c1,c2)endl; return 0; 调用模板函数调用模板函数, , 此时此时ATAT被被doubledouble替代替代调用模板函数调用模板函数, , 此此时时ATAT被被charchar替代替代调用非模板函数调用非模板函数程序运行结果为程序运行结果为: 调用非模板函数调用非模板函数:较大的整数是较大的整数是:56调用模板函数调用模板函数:较大的双精度型数是较大的双精度型数是:4656.34调用模板函数调用模板函数:较大的字符串是较大的字符串是:n8/5/202417第4章 串 8.3 类模板 所谓类模板,实际上是建立一个通用类,其数据成员、成员函数的返回类型和形参类型不具体指定
18、,用一个虚拟的类型来代表。 使用类模板定义对象时,系统会根据实参的类型(模板实参)来取代类模板中虚拟类型从而实现了不同类的功能。 8/5/202418第4章 串 定义一个类模板,格式如下:定义一个类模板,格式如下:或或 template template Typeclass class 类名类名 类成员声明类成员声明 ;template template Typeclass class 类名类名 类成员声明类成员声明 ; template template是一个是一个声明模板的关键字声明模板的关键字 TypeType是类型参数是类型参数8/5/202419第4章 串例如例如, ,建立一个用来实
19、现求三个数之和的类模板。建立一个用来实现求三个数之和的类模板。templatetypename template / / 模板声明模板声明, ,其中其中T T为类型参数为类型参数class Three / class Three / 类模板名为类模板名为ThreeThree public: public: Three( Three(T T a,T b, a,T b,T T c) c) x=a; y=b; z=c; x=a; y=b; z=c; T T sum() sum() return x+y+z; return x+y+z; private: private: T T x,y,z; x,y
20、,z;类型参数类型参数 在类声明中,欲采用在类声明中,欲采用通用数据类型的通用数据类型的数据成数据成员员、成员函数成员函数的参数或的参数或返回类型前面需加上返回类型前面需加上T T。8/5/202420第4章 串 用类模板定义对象时,采用以下形式: 使用上面求三个数之和的类模板的主函数可写成: int main() int main() Three Three sum3_1sum3_1(3,5,7);(3,5,7); Three Three sum3_2sum3_2(12.34,34.56,56.78);(12.34,34.56,56.78); cout cout三个数之和是三个数之和是: s
21、um3_1.sum()endl;: sum3_1.sum()endl; cout cout三个数之和值是三个数之和值是: sum3_2.sum()endl;: sum3_2.sum()endl; return 0; return 0; 类模板名 对象名;类模板名 对象名(实参表列);8/5/202421第4章 串#include /#include /例例8.6 8.6 类模板类模板ThreeThree的使用。的使用。using namespace std;using namespace std;templatetypenametemplate / / 模板声明模板声明, ,其中其中T T为类
22、型参数为类型参数class Three / class Three / 类模板名为类模板名为ThreeThree public: public: Three( Three(T T a, a,T T b, b,T T c) x=a; y=b; z=c; c) x=a; y=b; z=c; T T sum() return x+y+z; sum() return x+y+z; private: private: T T x,y,z; x,y,z; ;int main()int main() Three sum3_1(3,5,7);Three sum3_1(3,5,7); Three sum3_2(
23、12.34,34.56,56.78); Three sum3_2(12.34,34.56,56.78); cout cout三个整数之和是三个整数之和是: sum3_1.sum()endl;: sum3_1.sum()endl; cout cout三个双精度数之和是三个双精度数之和是: sum3_2.sum()endl;: sum3_2.sum()endl; return 0; return 0; 用类模板定义对象用类模板定义对象sum3_1,sum3_1,此时此时T T被被intint替代替代 用类模板定义对象用类模板定义对象sum3_2,sum3_2,此时此时T T被被doubledoub
24、le替代替代程序运行结果如下程序运行结果如下: :三个整数之和是三个整数之和是:15:15三个双精度数之和是三个双精度数之和是:103.68:103.68 8/5/202422第4章 串 类模板中的成员函数可以在类模板体外定义。此时,若成员函数中有类型参数存在,则C+有一些特殊的规定: (1)需要在成员函数定义之前进行模板声明; (2)在成员函数名前缀上“类名:”。 在类模板体外定义的成员函数的一般形式如下: 例如, 上例中成员函数sum在类模板体外定义时,应该写成: templatetemplate T T ThreeThree :sum()sum() return x+y+z; retur
25、n x+y+z; template typename template 函数类型函数类型 类名类名 :成员函数名成员函数名( (形参表形参表) ) 8/5/202423第4章 串#include /#include /例例8.7 8.7 在类模板体外定义成员函数。在类模板体外定义成员函数。using namespace std;using namespace std;templatetypenametemplate / /模板声明模板声明, ,其中其中T T为类型参数为类型参数class Three class Three public: public: Three(Three(T T a,
26、a,T T b, b,T T c); c); T sum();T sum(); private: private: T T x,y,z; ; x,y,z; ;templatetemplateThree:Three(T a, T b,T c)Three:Three(T a, T b,T c) x=a; y=b; z=c; x=a; y=b; z=c; template template T Three:sum()T Three:sum() return x+y+z; return x+y+z; 在类模板体外定义构造函数在类模板体外定义构造函数, ,在函在函数名前缀上数名前缀上“类名类名 :”:”
27、在类模板体外定义成员函数在类模板体外定义成员函数sum, sum, 返回类型为返回类型为T,T,函数名前函数名前缀上缀上“类名类名 :”:”在构造函数定义之前进行模板声明在构造函数定义之前进行模板声明在成员函数定义之前进行模板声明在成员函数定义之前进行模板声明8/5/202424第4章 串int main() int main() Three sum3_1(3,5,7);Three sum3_1(3,5,7); Three sum3_2(12.34,34.56,56.78);Three sum3_2(12.34,34.56,56.78); cout cout三个整数之和是三个整数之和是: su
28、m3_1.sum()endl;: sum3_1.sum()endl; cout cout三个双精度数之和是三个双精度数之和是: sum3_2.sum()endl;: sum3_2.sum()endl; return 0; return 0; 用类模板定义对象用类模板定义对象sum3_1,sum3_1,此此时类型参数时类型参数T T被被intint替代替代用类模板定义对象用类模板定义对象sum3_2,sum3_2,此此时类型参数时类型参数T T被被doubledouble替代替代程序运行结果如下程序运行结果如下: :三个整数之和是三个整数之和是:15:15三个双精度数之和是三个双精度数之和是:1
29、03.68:103.688/5/202425第4章 串 8/5/202426第4章 串#include /#include /例例8.98.9template template class myclass class myclass T1 i; T1 i; T2 j; T2 j; public: public: myclass(T1 a,T2 b) i=a; j=b; myclass(T1 a,T2 b) i=a; j=b; void show( )couti=i j=jendl; void show( )couti=i j=jendl; main( ) main( ) myclass myc
30、lass ob1(12,0.15); ob1(12,0.15); myclass myclass ob2( ob2( x x ,This is a test);,This is a test); ob1.show( ); ob1.show( ); ob2.show( ); ob2.show( ); return 0; return 0; T1T1和和T2T2是类型参数是类型参数 运行结果如下:运行结果如下: i=12 j=0.15 i=12 j=0.15 i=x j=This is a test i=x j=This is a test 模板类可以有多个类型参数模板类可以有多个类型参数 用类模板定义对象用类模板定义对象ob1,ob1,此时此时T1T1、T2T2分别被分别被intint与与doubledouble取代取代 用类模板定义对象用类模板定义对象ob2,ob2,此时此时T1T1、T2T2分别被分别被charchar与与char*char*取代取代