10.1函数模板10.2类模板第10讲模板模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成员函数的参数、返回值取得任意类型。由于C++语言的程序结构主要由函数和类构成的,因此,模板也具有两种形式:函数模板类模板模板是一种将数据类型参数化的工具,是C++语言的一个重要特征。10.1函数模板10.1.1为什么引进函数模板?引进函数模板可以解决函数重载问题,减少代码的书写。案例1利用重载函数求绝对值:#includeiostream.h#includemath.hintf(inti){returni0?i:-i;}//函数重载longintf(longinti){returni0?i:-i;}//函数重载doublef(floati){returni0?i:-i;}//函数重载voidmain(){inta;longintb;floatc;//声明变量cinabc;cout整型:f(a)长整型:f(b)浮点型:f(c)endl;}#includeiostream.h#includemath.hclassABS//求绝对值{public:intf(inti){returnabs(i);}//函数重载longintf(longinti){returnlabs(i);}//函数重载doublef(floati){returnfabs(i);}//函数重载};voidmain(){ABSn;//声明对象inta;longintb;floatc;//声明变量cinabc;cout整型:n.f(a)长整型:n.f(b)浮点型:n.f(c)endl;}求绝对值方法二:templatetypenameTTabs(Tvalue){returnvalue0?value:-value;}方法三利用函数模板,求绝对值的函数只要声明一个函数模板:voidmain(){inta;longintb;floatc;//声明变量cinabc;cout整型:abs(a)长整型:abs(b)浮点:abs(c)endl;}第一次使用函数模板abs()时,实参为整数,由此可以推导出函数模板中的参数类型T为整型,函数的返回值也是整型。第二次调用abs()时实参为长整型,由此推导出函数模板中的参数类型T为长整型,函数的返回值为长整型。在主程序中可以这样使用函数模板:利用函数模板,可以建立一个具有通用功能的函数,支持不同的函数参数和返回值,达到减少代码书写量的目的。函数模板的定义形式如下:templateclassT返回值类型函数名(参数表){函数体}类型形参T代表在函数模板中要使用的通用类型,在该函数的调用过程中,T被实参的类型具体化。10.1.2函数模板的定义与使用关键词class或typename与T一起说明用户定义的数据类型函数模板实际上是定义了一类函数,对有些参数或数据成员的数据类型并不具体指定,而是作为模板的参数。等到使用模板时再根据实参的数据类型来确定模板参数的类型,得到模板的实例,称为模板的实例化。例如:templatetypenameTTabs(Tvalue){returnvalue0?value:-value;}若使用模板时:abs(5);//将模板参数的类型实例化为整型abs(-3.8);//将模板参数的类型实例化为实型函数模板实例化后生成的函数称为模板函数。在程序中可用不同类型的实参来调用同一个函数,减少了代码的书写。#includeiostream.htemplateclassT//函数模板(两数交换)voidswap(T&x,T&y){Ttemp=x;x=y;y=temp;}templateclassT//函数模板(冒泡排序)voidsort(T*v,intn)//参数中有参数化类型的参数,也有普通类型的参数{for(inti=1;in;i++)for(intj=0;jn-1;j++)if(v[j]v[j+1])swap(v[j],v[j+1]);//调用函数模板实例化后生成的模板函数}案例2编写冒泡排序的函数模板并实现排序。templateclassT//print函数模板(显示输出)voidprint(T*v,intn){for(inti=0;in;i++)coutv[i];coutendl;}voidmain(){shorta[10]={22,11,44,66,88,99,0,33,55,77};cout排序前:;print(a,10);sort(a,10);//对整型数据排序cout排序后:;print(a,10);chars[]=zcpkvrehaq;cout排序前:;print(s,10);sort(s,10);//对字符型数据排序cout排序后:;print(s,10);}(续)在C++中,不仅可以设计函数模板来满足对不同类型数据的同一功能要求,还可以设计类模板来表示具有相同处理方法的数据对象集。10.2类模板若把类看作包含某些类型数据的框架,将数据类型从类中分离出来形成一个通用的数据类型T,并允许具体数据类型的类能使用数据类型T提供的不同操作,这将避免因为类的数据类型的不同而产生重复性的设计。类模板不是类,只是类的描述。在编译时,编译器将类模板与某种特定的数据类型联系起来,就产生了一个真实的类,即类的实例化。C++语言中的类模板的语法定义如下:template模板参数表class类名{类体}模板参数表中的内容可以为:class标识符或类型说明符标识符注当模板参数表中同时包含多项内容时,各项内容之间以逗号隔开。与函数模板类似,类模板只有使用的时候才被具体化为某一种类型。使用模板类来产生对象时,按如下形式声明:模板模板参数表对象名1,......对象名n;关键词#includeiostream.htemplateclassType//声明类模板classNum{Typea,b;public:Num(){}//无参数的构造函数Num(Typex,Typey):a(x),b(y){}//带参数的构造函数intCompare()//成员函数,比较两个数的大小{if(ab)return1;elseif(a==b)return0;elsereturn-1;}TypeMaxNum(){returnab?a:b;}//找大数的函数TypeMinNum(){returnab?b:a;}//找小数的函数voidSetNum(Types,Typet){a=s;b=t;}};案例3类模板应用举例(两个数比较大小)。voidmain(){Numintx(5,8);//声明带参数的对象xcoutMax:x.MaxNum()Min:x.MinNum()endl;if(x.Compare()==1)coutabendl;if(x.Compare()==0)couta=bendl;if(x.Compare()==-1)coutabendl;}voidmain()//主函数的另一种写法{Numinty;//声明不带参数的对象yinta,b;cinab;y.SetNum(a,b);coutMax:y.MaxNum()Min:y.MinNum()endl;if(y.Compare()==1)coutabendl;if(y.Compare()==0)couta=bendl;if(y.Compare()==-1)coutabendl;}案例4类模板应用举例(三个数求最大值)。#includeiostream.h#includeconio.htemplateclassT//声明类模板MaxclassMax{private:Titem1,item2,item3;//类型为T,在该类的对象生成时具体化public:Max(){}Max(Tfir,Tsec,Tthi);TGetMaxItem();//求3个数中的最大值并返回T类型数voidSetItem(Tfir,Tsec,Tthi);//设置类中的3个变量的值};templateclassT//类模板的实现MaxT::Max(Tfir,Tsec,Tthi):item1(fir),item2(sec),item3(thi){}templateclassTvoidMaxT::SetItem(Tfir,Tsec,Tthi){item1=fir;item2=sec;item3=thi;}templateclassTTMaxT::GetMaxItem()//求最大值函数{Tmax;max=item1item2?item1:item2;max=maxitem3?max:item3;returnmax;}voidmain(){MaxintintMax(1,5,9);//声明对象,数据类型为intMaxdoubledoubleMax(11.2,21.3,-31.4);coutintMax.GetMaxItem()endl;coutdoubleMax.GetMaxItem()endl;}921.3小结模板实质上是C++对参数化多态在语法上提供的支持。模板定义需要关键字template,将需要参数化的部分用一个形式变量来表示。模板参数的替换过程是在编译期间完成的。模板分函数模板和类模板。模板就是将一段程序所处理的对象的数据类型进行参数化,可以使程序能够处理某个范围内的各种类型的对象,也称参数化多态性。