您好,欢迎访问三七文档
当前位置:首页 > 机械/制造/汽车 > 机械/模具设计 > C 程序设计 第12节 模板
第12章模板本讲内容提要函数模板函数模板模板函数模板实参的省略类模板类模板的概念与定义模板类类模板的继承与派生请看下面的函数:voidadd(inta[],intb[],intsize){for(inti=0;isize;i++)b[i]+=a[i];}voidadd(floata[],floatb[],floatsize){for(inti=0;isize;i++)b[i]+=a[i];}voidadd(doublea[],floatb[],doublesize){for(inti=0;isize;i++)b[i]+=a[i];}……如果不限定数组的类型为整型,则……一、函数模板函数模板是通过对参数类型进行参数化后,获取有相同形式的函数体。它是一个通用函数,它可适应一定范围内的不同类型对象的操作。函数模板将代表着不同类型的一组函数,它们都使用相同的代码,这样可以实现代码重用,避免重复劳动,又可增强程序的安全性。1.函数模板利用函数模板解决上述问题。函数模板的定义格式:template(参数化类型名表)类型函数名(模板参数表){函数体}参数化类型名表又称模板参数表,多个表项用逗号分隔。每个表项称为一个模板参数(模板形参)。格式如下:class参数名或typename参数名或类型修饰参数名add模板可以定义为:其中,“”括起部分就是模板的形参表,T是一个虚拟类型参数。注意,可以用多个虚拟参数构成模板形参表。不但普通函数可以声明为函数模板,类的成员函数也可以声明为函数模板。templateclassTvoidadd(Ta[],Tb[],intsize){for(inti=0;isize;i++)b[i]+=a[i];}2.模板函数函数模板是模板函数的一个样板,它可以生成多个重载的模板函数,这些模板函数重用函数体代码。模板函数是函数模板的一个实例。函数模板的实例化(instantiation)longfloatx[]={1,2,3,4,5,6},y[]={7,8,9,10,11,12};add(x,y,6);voidadd(floata[],floatb[],floatsize){for(inti=0;isize;i++)b[i]+=a[i];}templatetypenameT1,typenameT2voidadd(T1a[],T2b[],intsize){for(inti=0;isize;i++)b[i]+=a[i];}例12.1:问题:分析程序输出结果。templateclassstypevoidbubble(stype*item,intcount){stypebubb;for(inti=0;i=count-1;i++)for(intj=i+1;jcount;j++)if(item[i]item[j]){bubb=item[i];item[i]=item[j];item[j]=bubb;}}#includeiostream.h#includestring.htemplateclassstypevoidbubble(stype*item,intcount);voidmain(){intnums1[]={4,7,2,9,3,7,6,1};bubble(nums1,8);coutThesortednumbersare;for(inti(0);i8;i++)coutnums1[i];coutendl;doublenums2[]={2.3,5.3,6.7,3.9,7.2,1.5};bubble(nums2,6);coutThesortednumbersare;for(i=0;i6;i++)coutnums2[i];coutendl;}3.模板实参的省略模板实参的省略是有条件的。以下四种情况模板实参不能省略:从模板函数实参表获得的信息有矛盾。需要获得特定类型的返回值,而不管参数的类型如何。虚拟类型参数没有出现在模板函数的形参表中。函数模板含有常规形参。从模板函数实参表获得的信息有矛盾。例如:templatetypenameTTadd(Ta,Tb){returna+b;}若调用函数的语句为:coutadd(3,5);则编译系统无论是从3还是5所获得的信息都是T对应于int,因此可顺利地生成如下模板函数:intadd(inta,intb){returna+b;}调用语句变为:coutaddint(3.0,5);其中,紧跟在函数名后的int就是模板实参表,此时,编译系统生成如下的模板函数:intadd(inta,intb){returna+b;}需要获得特定类型的返回值,而不管参数的类型如何。例如,如果需要add返回一个int型的值,那么直接以addint(a,b);形式调用即可。虚拟类型参数没有出现在模板函数的形参表中。由于虚拟类型参数没有出现在模板函数的形参表中,所以调用时不可能从模板函数的实参表中获得相应的信息,因此无法省略。例12.2分析程序输出结果。#includeiostreamusingnamespacestd;templatetypenameT1,typenameT2,typenameT3T2add(T1a,T3b){returna+b;}voidmain(){coutshowpoint;coutadddouble,int(3,5L)endl;coutaddint,double,long(3,5L)endl;}程序运行结果为:88.00000函数模板含有常规形参。当函数模板含有常规形参时,如果常规参数的信息无法从模板函数的实参表中获得,则在调用时必须显式的给出对应于常规参数的模板实参。例12.3分析程序输出结果。#includeiostreamusingnamespacestd;templateclassT,introwssum(Tdata[],T&result){result=0;for(inti=0;irows;i++)result+=data[i];}intmain(){intd[3]={1,2,3};intr;//此处必须显式给出对应于常规参数的模板实参sumint,3(d,r);coutsum=rendl;return0;}程序运行结果为:sum=6二、类模板1.为何要引进类模板?按不同的方式重用相同的代码使代码参数化(通用化),即不受类型和操作的影响使用类模板所定义的一种类类型,类中的某些数据成员和某些成员函数的参数及返回值可以选取一定范围内的多种类型,从而实现代码重用。是一种参数化类型的类,是类的生成器。讨论引进类模板的必要性有如下程序:Node是链表的节点类,List为链表类。classNode{……};classList{public:List();~List();voidAdd(Node&);voidRemove(Node&);Node*Find(Node&);……};//该类的实现部分略……通用化修改,使用参数TclassList{public:List();~List();voidAdd(T&);voidRemove(T&);Node*Find(T&);……};//该类的实现部分略……2.类模板(1)类模板的定义template模板参数表class类名{类体说明};//类体实现模板参数表class标识符例如,array.h文件中类模板的定义(2)用类模板定义对象的格式是:类名模板实参表对象名(构造函数实参表);3.模板类模板类在定义了类模板后,可根据需要生成相应的模板类。即,对模板参数,指定具体的类型。例如,当指定AType为int型时,生成模板类arrayint利用模板类创建对象格式如下:arrayinta1=10;例12.4:问题:分析程序输出结果。#includeiostream.h#includestdlib.htemplateclassTclassstack{public:stack(intsize);~stack(){delete[]stck;}voidpush(Ti);Tpop();private:inttos,length;T*stck;};程序运行结果为:987654321022.52017.51512.5107.552.50abcdefghijtemplateclassTstackT::stack(intsize)//构造函数{stck=newT[size];if(!stck){coutcannotallocatestack.\n;exit(1);}length=size;//栈长度tos=0;}templateclassTvoidstackT::push(Ti)//入栈{if(tos==length)//满栈coutStackisfull.\n;stck[tos]=i;tos++;}templateclassTTstackT::pop()//出栈{if(tos==0)coutStackunderflow.\n;tos--;returnstck[tos];}voidmain(){stackinta(10);//模板类stackintstackdoubleb(10);//模板类stackdoublestackcharc(10);//模板类stackcharfor(inti=0;i10;i++)a.push(i);for(i=0;i10;i++)b.push(i*2.5);for(i=0;i10;i++)couta.pop()'';coutendl;for(i=0;i10;i++)coutb.pop()'';coutendl;for(i=0;i10;i++)c.push((char)'j'-i);for(i=0;i10;i++)coutc.pop()'';coutendl;}4.类模板的继承与派生模板类的派生与普通类一样,也分为公有派生类、保护派生类和私有派生类三种。模板派生类中成员的访问控制规则与普通类也是一样的。下面给出常见的几种情况:普通类继承类模板模板类继承普通类模板类继承模板类模板类继承模板参数给出的基类普通类继承类模板可以通过继承类模板的一个实例来声明一个类,例如:templateclassTclassTBase{Tdata;……};classDerived:publicTBaseint{……};模板类继承普通类模板类TDerived继承了普通类TBase,这种情况十分常见。例如:classTBase{……};templateclassTclassTDerived:publicTBase{Tdata;……};模板类继承模板类例如:templateclassTclassTBase{Tdata1;……};templateclassT1,classT2classTDerived:publicTBaseT1{T2data2;……};模板类继承模板参数给出的基类继承哪个基类由模板参数决定。例12.5分析程序输出结果。#includeiostreamusingnamespacestd;classBaseA{public:BaseA(){coutBaseAfounedendl;}};classBaseB{public:BaseB(){coutBaseBfounedendl;}};templatetypenameT,intvalueclassBaseC{private:Tdata;public:BaseC(Tn=value):data(n
本文标题:C 程序设计 第12节 模板
链接地址:https://www.777doc.com/doc-4003204 .html