-1《C++语言及编程技巧》主讲:匡纲要国防科技大学电子科学与工程学院·湖南长沙·-2第21讲模板-3第22讲模板模板概念13.1函数模板与模板函数13.2重载模板函数13.3类模板与模板类13.4类模板用作函数模板的参数13.5标准模板库STL简述-4模板的概念所谓模板是一种使用无类型参数来产生一系列函数或类的机制,是C++的一个重要特性。它的实现,方便了更大规模的软件开发。若一个程序的功能是对某种特定的数据类型进行处理,则可以将所处理的数据类型说明为参数,以便在其他数据类型的情况下使用,这就是模板的由来。模板是以一种完全通用的方法来设计函数或类而不必预先说明将被使用的每个对象的类型。通过模板可以产生类或函数的集合,使它们操作不同的数据类型,从而避免需要为每一种数据类型产生一个单独的类或函数。-5例如,设计一个求两参数最大值的函数,不使用模板时,需要定义四个函数:intmax(inta,intb){return(ab)?a,b;}longmax(longa,longb){return(ab)?a,b;}doublemax(doublea,doubleb){return(ab)?a,b;}charmax(chara,charb){return(ab)?a,b;}若使用模板,则只定义一个函数:Templateclasstypetypemax(typea,typeb){return(ab)?a,b;}模板的概念-6C++程序由类和函数组成,模板也分为类模板(classtemplate)和函数模板(functiontemplate)。在说明了一个函数模板后,当编译系统发现有一个对应的函数调用时,将根据实参中的类型来确认是否匹配函数模板中对应的形参,然后生成一个重载函数。该重载函数的定义体与函数模板的函数定义体相同,它称之为模板函数(templatefunction)。同样,在说明了一个类模板之后,可以创建类模板的实例,即生成模板类。模板的概念-713.1函数模板与模板函数C++提供的函数模板可以定义一个对任何类型变量进行操作的函数,从而大大增强了函数设计的通用性。使用函数模板的方法是先说明函数模板,然后实例化成相应的模板函数进行调用执行。函数模板说明函数模板的一般说明形式如下:template模板形参表返回值类型函数名(模板函数形参表){//函数定义体}其定义形式:typename模板参数名函数模板定义或class模板参数名类模板定义其实typename和class在这里具有相同的含义。-8templateclassT//也可写成:templatetypenameTTmin(Ta[],intn){inti;Tminv=a[0];for(i=1;in;i++)if(minva[i])minv=a[i];returnminv;}例13-1:编写一个对具有n个元素的数组a[]求最小值的程序,要求将求最小值的函数设计成函数模板。13.1函数模板与模板函数-9函数模板定义的实例化---模板函数函数模板只是说明,不能直接执行,需要实例化为模板函数后才能执行。当编译系统发现有一个函数调用:函数名(实参表);时,将根据实参表中的类型生成一个重载函数即模板函数。该模板函数的定义体与函数模板的函数定义体相同,而形参表的类型则以实参表的实际类型为依据。在模板函数被实例化之前,必须在函数的某个地方首先说明它(可能不进行定义),这样,就可以到后面再定义模板。和一般函数一样,如果函数模板的定义在首次调用之前,函数模板的定义就是对它的说明。定义之后的首次调用就是对模板函数的实例化。13.1函数模板与模板函数-10对模板函数的说明和定义必须是全局作用域。模板不能被说明为类的成员函数。模板函数有一个特点,虽然模板参数T可以实例化成各种类型,但是采用模板参数T的各参数之间必须保持完全一致的类型。模板类型并不具有隐式的类型转换,例如在int与char之间、float与int之间、float与double之间等的隐式类型转换。而这种转换在C++中是非常普遍的。例13-1:函数模板仅定义了函数的形状,编译器将根据实际的数据类型参量在内部产生一个相应的参数模板,一个模板函数的数据类型参量必须全部使用模板形参。13.1函数模板与模板函数-11函数模板方法克服了C语言解决上述问题时用大量不同函数名表示相似功能的坏习惯;克服了宏定义不能进行参数类型检查的弊端;克服了C++函数重载用相同函数名字重写几个函数的繁琐。因而,函数模板是C++中功能最强的特性之一,具有宏定义和重载的共同优点,是提高软件代码重用率的重要手段。13.1函数模板与模板函数-12#includeiostream.htemplateclassTTmin(Ta[],intn){inti;Tminv=a[0];for(i=1;in;i++)if(minva[i])minv=a[i];returnminv;}voidmain(){inaa[]={1,3,0,2,7,6,4,5,2};doubleb[]={1.2,-3.4,6.8,9,8};cout”a数组的最小值为:”min(a,9)endl;cout”b数组的最小值为:”min(b,4)endl;}此程序的运行结果为:a数组的最小值为:0b数组的最小值为:-3.4对例13-1中定义的函数模板实例化如下:13.1函数模板与模板函数-13//programc13_02.cpp#includeiostreamusingnamespacestd;templatetypenameTvoidswap(T*p,T*q){Ttemp=*p;*p=*q;*q=temp;}templatetypenameTvoidselectsort(Ta[],constintn){for(inti=0;in-1;i++)for(intj=i;jn;j++)if(a[i]a[j])swap(&a[i],&a[j]);}templatetypenameTvoidprint(Ta[],constintn){for(inti=0;in;i++)if(in-1)couta[i],;elsecouta[i];coutendl;}voidmain(){ints[]={7,8,6,4,9};charc[]=C++andJava;doubled[]={76.9,81.2,67.4,59.1,90.2,88.8,60.3,77.2};intslen,clen,dlen;slen=sizeof(s)/sizeof(int);clen=strlen(c);dlen=sizeof(d)/sizeof(double);coutIntegerarraysis:endl;print(s,slen);selectsort(s,slen);coutAftersorting,nowintegerarraysis:endl;print(s,slen);coutendl;coutCharacterarraycis:endl;print(c,clen);selectsort(c,clen);coutAftersorting,nowcharacterarraycis:endl;print(c,clen);coutendl;coutDoublearraydis:endl;print(d,dlen);selectsort(d,dlen);coutAftersorting,nowdoublearraydis:endl;print(d,dlen);coutendl;}例13-2:利用模板函数,实现一维数组进行排序并输出一维数组元素。13.1函数模板与模板函数-1413.2重载模板函数例:Tlargest(Ti,Tj,Tk){Tmax=i;if(bmax)max=b;if(cmax)max=c;returnmax;}上述函数模板定义,可以实现int型数据、double型数据或char型数据的最大值,但它不适用于求字符串数据的最大值。为C++程序能在原有函数模板的基础上,扩展成允许求字符串的最大值,可以另写一个与函数模板的函数同名的函数物重载函数,它能实现所需功能。char*largest(char*a,char*b,char*c){char*max;strcpy(max,a);if(strcmp(b,max)0)strcpy(max,b);if(strcmp(c,max)0)strcpy(max,c);returnmax;}函数char*max(char*,char*,char*)中的名字与函数模板的名字相同,但操作不同,函数体中的比较采用了字符串比较函数,这就是模板函数的重载。编译器在处理时,首先匹配重载函数,然后再寻求模板的匹配。-15voidswap(char*p,char*q){char*temp;strcpy(temp,p);strcpy(p,q);strcpy(q,temp);}voidselectsort(char*a[],constintn){for(inti=0;in-1;i++)for(intj=i;jn;j++)if(strcmp(a[i],a[j])0)swap(&a[i],&a[j]);}voidprint(char*a[],constintn){for(inti=0;in;i++)if(in-1)couta[i],;elsecouta[i];coutendl;}例13-3:在例13-2的基础上增加三个对应的重载模板函数。templatetypenameTvoidswap(T*p,T*q){Ttemp=*p;*p=*q;*q=temp;}templatetypenameTvoidselectsort(Ta[],constintn){for(inti=0;in-1;i++)for(intj=i;jn;j++)if(a[i]a[j])swap(&a[i],&a[j]);}templatetypenameTvoidprint(Ta[],constintn){for(inti=0;in;i++)if(in-1)couta[i],;elsecouta[i];coutendl;}13.2重载模板函数-16设:ints[]={7,8,6,4,9};charc[]=C++andJava;doubled[]=d{76.9,81.2,67.4,59.1,90.2,88.8,60.3,77.2};char*a[]={C++,Pascal,Java,Ada,FORTRAN,COBAOL};则:selectsort(s,5);print(s,5);selectsort(c,strlen(c));print(c,strlen(c));selectectsort(d,8);print(d,8);selectsort(a,6);print(a,6);其结果是什么?请思考!13.2重载模板函数-1713.3类模板与模板类类模板与函数模板类似,它可以为各种不同的数据类型定义一种模板,在引用时使用不同的数据类型实例化该类模板,从而形成一个类的集合。类模板实际上是函数模板的推广。可以用相同的类模板来组建任何类型的对象集合。在传统C++中,可能有一个浮点数类或者一个整数类,如果使用类模板,可以定义一个对两者都适用的类number。类模板说明类模板说明的一般形式是:-18template类型形参表class类名{//类说明体};template类型形参表返回类型类名类型名表::成员函数1(形参表){//成员函数定义体}template类型形参表返回类型类名类型名表::成员函数2(形参表){//成员函数定义体}…template类型形参