南开大学C++课件第9章模板及其应用_第1页
南开大学C++课件第9章模板及其应用_第2页
南开大学C++课件第9章模板及其应用_第3页
南开大学C++课件第9章模板及其应用_第4页
南开大学C++课件第9章模板及其应用_第5页
已阅读5页,还剩44页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1,第9章模板及其应用,9.1函数模板9.2类模板9.3关于类模板若干问题的说明9.4程序实例本章介绍函数模板与类模板的定义及其使用方法。通过使用模板,可使所编程序更加紧凑,增加程序的通用性及可重用性。,2,9.1函数模板9.1.1函数模板的概念及说明9.1.2函数模板的应用举例-9.1.1函数模板的概念及说明-参看书p299-301通常设计的算法(处理语句)是可以处理多种数据类型的,但目前处理相同的问题,仍要分别定义多个类似的函数。,3,intmax(inta,intb)if(ab)returna;elsereturnb;doublemax(doublea,doubleb)if(ab)returna;elsereturnb;charmax(chara,charb).,4,实际上,若“提取”出一个可变化的类型参数T,则可“综合”成为如下的同一个函数(模板),它实际上代表着一组函数:Tmax(Ta,Tb)if(ab)returna;elsereturnb;在C+中定义完整的函数模板max时,格式如下:templateTmax(Ta,Tb)if(ab)returna;elsereturnb;,5,函数模板定义的一般格式为:template返回类型函数模板名(形参表)函数体注意:1)应在“返回类型”或“形参表”或“函数体”中使用上述的“类型形参名”。2)调用处则类似于一般函数,用户只需给出具体的实参。3)模板函数调用时,不进行实参到形参类型的自动转换。,6,9.1.2函数模板的应用举例-参看书p302,1.函数模板例1定义一个函数模板max,而后对它进行不同的调用。#includetemplateTmax(Ta,Tb)if(ab)returna;elsereturnb;,7,voidmain()inti1=-11,i2=0;doubled1,d2;coutd1d2;coutmax(d1,d2)endl;/coutmax(23,-5.6)=max(23,-5.6)max(c1,c2)=Tmax(f,k)=kinputdoubled1,d2:123.4599.67d1=123.45,d2=99.67=max(d1,d2)=123.452.函数模板例2-函数模板与函数重载定义一个函数模板与一个函数,它们都叫做min,C+允许这种函数模板与函数同名的所谓重载使用方法。但注意,在这种情况下,每当遇见函数调用时,C+编译器都将首先检查是否存在重载函数,若匹配成功则调用该函数,否则再去匹配函数模板。,9,#include#includetemplatetypemin(typea,typeb)/type型的a与b要能够进行“”比较运算!return(ab?a:b);char*min(char*a,char*b)/函数min,字符串型参数,不能直接使用“”来进行比较return(strcmp(a,b)0?a:b);voidmain()coutmin(3,-10)endl;/使用函数模板coutmin(2.5,99.5)endl;coutmin(m,c)endl;char*str1=TheCprogram,*str2=TheC+program;coutmin(str1,str2)endl;/使用重载函数!,10,3.函数模板例3-二函数模板重载定义两个函数模板,它们都叫做sum,都使用了一个类型参数Type,但两者的形参个数不同,C+允许使用这种函数模板重载的方法。注意,参数表中允许出现与类型形参Type无关的其它类型的参数,如“intsize”。#includetemplateTypesum(Type*array,intsize)/求array数组前size个元素之和Typetotal=0;for(inti=0;isize;i+)total+=*(array+i);returntotal;,11,templateTypesum(Type*a1,Type*a2,intsize)/求a1数组与a2数组前size个元素之和Typetotal=0;for(inti=0;isize;i+)total+=a1i+a2i;returntotal;voidmain()inta110,a28;floataf10;./为数组分量定值coutsum(a1,10)endl;/求出a1数组前10个元素之和并输出coutsum(af,10)endl;coutsum(a1,a2,8)endl;/求a1与a2数组前8个元素之和并输出,12,9.2类模板9.2.1一个队列类模板9.2.2类模板说明9.2.3使用类型参数和普通参数的类模板,13,9.3.1设计一个队列类模板-参看书p305,队列与栈不同,对数据采用“先进先出”-FIFO的管理方式(而栈则使用“先进后出”-FILO方式)。队列数据放于作为类成员的动态数组queue之中,在构造函数中,将通过new来生成该动态数组,动态数组queue的大小由类的私有数据成员Maxsize之值来确定。但注意,此示例并没有循环使用上述的动态数组queue空间。即是说,队列中至多可以存放Maxsize个数据项,即使取走若干项后有了空闲空间后也不可重新进行使用。若稍加改造,使存取数据时首先通过对下标进行模Maxsize的运算,则可实现循环使用动态数组queue空间的功能,我们把它留作一个练习。,14,#include#includetemplateclassQueueintMaxsize;/队列的大小intfront,rear;/元素放在queuefront+1到queuerear之中keytype*queue;/动态数组queue,用来存放队列数据public:Queue(intsize)/构造函数,生成动态数组来存放队列数据Maxsize=size;queue=newkeytypeMaxsize;front=rear=-1;/意味着队列为空;,15,intIsFull()if(rear=Maxsize-1)return1;elsereturn0;intIsEmpty()if(front=rear)return1;elsereturn0;voidAdd(constkeytype,16,/Delete在类体外定义,函数名前要加类限定符“Queue:”templatekeytypeQueue:Delete(void)if(IsEmpty()coutvoidQueue:Add(constkeytype,17,voidmain()inti=0;QueueQi(10);QueueQf1(10),Qf2(10);while(!Qi.IsFull()/Qi中只能盛10个数Qi.Add(2*i+);/Qi中:0,2,4,6,8,10,12,14,16,18Qf1.Add(3.0*i);/Qf1中:3,6,9,12,15,18,21,24,27,30for(i=0;i4;i+)/四次循环,每次总/先往Qf2的队列尾部加入两个数,而后又从首部删取一个数并输出Qf2.Add(4.5*Qi.Delete();/从Qi首删取一元素,乘以4.5,而后将其加入到Qf2尾部/四次循环往Qf2队列尾加入:0*4.5,2*4.5,4*4.5,6*4.5.程序执行后的显示结果如下:01.593,18,9.2.2类模板说明利用类模板(带类型参数或普通参数的类),一次就可定义出具有共性的一组类。即,可使得所定义类中的某些数据成员、某些成员函数的参数、某些成员函数的返回值都可以是任意类型的。,19,类模板定义格式如下:templateclass类模板名带上述类型形参或普通形参名的类定义体说明类型形参时,使用“class类型形参名”的方式,说明普通形参时,使用“普通形参名”的方式。注意:1)类定义体中应使用上述的“类型形参名”及“普通形参名”。2)利用类模板说明类对象时,要随类模板名同时给出对应于类型形参或普通形参的具体实参(从而实例化为一个具体的类)。说明格式为:类模板名注意:类型形参的相应实参为类型名,而普通形参的相应实参必须为一个常量。,20,3)类模板的成员函数既可以在类体内进行说明(自动按内联函数处理),也可以在类体外进行说明。在类体外说明(定义)时使用如下格式:template返回类型类模板名:函数名(形参表)./函数体;上述的“形参1的名字”来自于“形参1的说明”,由“甩掉”说明部分的“类型”而得,是对类型形参或普通形参的使用。而“类模板名:”所起的作用正是在类体外定义成员函数时在函数名前所加的类限定符!,21,例如,对具有一个类型参数T的类模板TestClass,在类体外定义其成员函数getData时的大致样式如下:templateTTestClass:getData(形参表)./函数体;其中的“TestClass:”所起的作用正是在类体外定义成员函数时在函数名前所加的类限定符!,22,9.2.3使用类型参数和普通参数的类模板,1仅使用类型参数的类模板#includetemplateclassTestClasspublic:Tbuffer10;/T类型的数据成员buffer数组大小固定为10(灵活性差!)TgetData(intj);/获取T类型buffer(数组)的第j个分量;templateTTestClass:getData(intj)return*(buffer+j);,23,voidmain()TestClassClassInstA;/char取代T,从而实例化为一个具体的类charcArr6=abcde;for(inti=0;i5;i+)ClassInstA.bufferi=cArri;for(i=0;i5;i+)charres=ClassInstA.getData(i);coutres;coutendl;,24,TestClassClassInstF;/实例化为另外一个具体的类doublefArr6=12.1,23.2,34.3,45.4,56.5,67.6;for(i=0;i6;i+)ClassInstF.bufferi=fArri-10;for(i=0;i6;i+)doubleres=ClassInstF.getData(i);coutres;coutendl;程序执行后的显示结果如下:abcde2.113.224.335.446.557.6,25,2仅使用普通参数(非类型参数)的类模板示例,#includetemplateclassTestClasspublic:intbufferi;/使buffer的大小可变化,但其类型则固定为int(灵活性差!)intgetData(intj);templateintTestClass:getData(intj)return*(buffer+j);,26,voidmain()TestClassClassInstF;doublefArr6=12.1,23.2,34.3,45.4,56.5,67.6;for(i=0;i6;i+)ClassInstF.bufferi=fArri-10;for(i=0;i6;i+)doubleres=ClassInstF.getData(i);coutres;coutendl;程序执行后的显示结果如下:21324354657,27,3既使用类型参数又使用普通参数的类模板示例,#include#includestring.htemplateclassTestClasspublic:Tbufferi;/T类型的buffer,其大小随普通形参i的值变化(灵活性大!)TgetData(intj);templateTTestClass:getData(intj)return*(buffer+j);,28,voidmain()TestClassClassInstA;charcArr6=abcde;strcpy(ClassInstA.buffer,cArr);for(inti=0;i5;i+)charres=ClassInstA.getData(i);coutres;coutendl;,29,TestClassClassInstF;doublefArr6=12.1,23.2,34.3,45.4,56.5,67.6;for(i=0;i6;i+)ClassInstF.bufferi=fArri-10;for(i=0;i6;i+)doubleres=ClassInstF.getData(i);coutres;coutendl;程序执行后的显示结果如下:abcde2.113.224.335.446.557.6,30,9.3关于类模板的若干问题说明9.3.1静态成员及友元9.3.2特例版本9.3.3按不同方法来派生类模板,31,1类模板的静态成员类模板也允许有静态成员。实际上,它们是类模板之实例化类的静态成员。也就是说,对于一个类模板的每一个实例化类,其所有的对象共享其静态成员。例如:templateclassCstaticTt;/类模板的静态成员t;类模板的静态成员在模板定义时是不会被创建的,其创建是在类的实例化之后。如:CAaiobj1,aiobj2;CAacobj1,acobj2;对象aiobj1和aiobj2将共享实例化类CA的静态成员intt,而对象acobj1,acobj2将共享实例化类CA的静态成员chart。,9.3.1静态成员及友元,32,2类模板的友元类模板定义中允许包含友元。我们讨论类模板中的友元函数,因为说明一个友元类,实际上相当于说明该类的成员函数都是友元函数。该友元函数为一般函数,则它将是该类模板的所有实例化类的友元函数。该友元函数为一函数模板,但其类型参数与类模板的类型参数无关。则该函数模板的所有实例化(函数)都是类模板的所有实例化类的友元。更复杂的情形是,该友元函数为一函数模板,且它与类模板的类型参数有关。例如,函数模板可以用该类模板作为其函数参数的类型。在友元函数模板定义与相应类模板(的类型参数)有关时,该友元函数模板的实例有可能只是该类模板的某些特定实例化(而不是所有实例化)类的友元。,9.3.1静态成员及友元,33,大多数类模板不能任意进行实例化。也就是说类模板的类型参数往往在实例化时不允许用任意的类(类型)作为“实参”。模板的“实参”不当,主要会在实例化后的函数成员调用中体现出来,例如templateclassstack/栈中元素类型为T的stack类模板TnumMAX;/num中存放栈的实际数据inttop;/top为栈顶位置public:stack()top=0;/构造函数voidpush(Ta)numtop+=a;/将数据a“压入”栈顶voidshowtop()/显示栈顶数据/模板中通用的showtop,显示栈顶的那一个T类型的数据/(必须为可直接通过运算符“”来显示的数据)if(top=0)coutstackisempty!endl;elsecoutTop_Member:numtop-1endl;,9.3.2特例版本,34,在上面的类模板stack中,以下的实例化都是可行的:stacki1,i2;stackc1,c2;stackf1,f2;等等。但如果采用用户定义类型而又未在该类中对运算符“com1,com2;由于在执行com1.showtop()函数时,将需要对complex类型的数据numtop-1通过使用运算符“就是不可行的了。,9.3.2特例版本,35,如果用户在上述情况下,需要使stack可行,可有几个办法。对于类complex追加插入运算符“:showtop()/专用于complex类型的showtop(专门补充的“特例版本”),显示栈顶的/那一个complex型数据。其中的stack为一个实例化后的模板类。if(top=0)coutstackisempty!endl;elsecoutTop_Member:numtop-1.get_r(),numtop-1.get_i()endl;,9.3.2特例版本,36,假设自定义的复数类型complex中具有公有的成员函数get_r()以及get_i(),用于获取复数的实部和虚部。如此,当实例化stack时将按该特例版本的定义进行。概括地说,当处理某一类模板中的可变类型T型数据时,如果处理算法并不能对所有的T类型取值做统一的处理,此时可通过使用专门补充的所谓特例版本来对具有特殊性的那些T类型取值做特殊处理。也可以对函数模板,或类模板的个别函数成员补充其“特例版本”定义。例如,可将该例的showtop功能进一步划分,让showtop调用另一个新增加的show函数,而由show函数具体考虑对两种情况的处理:一种处理可直接通过运算符“”来显示的数据,另一种“特例版本”专用于处理complex类型的数据。,9.3.2特例版本,37,实例,classcomplex/复数类型complexdoublereal,image;public:.;templateclassstackTdata20;inttop;public:voidshowtop(void);/显示栈顶数据.;,38,templatevoidstack:showtop(void)/通用的showtop/(T类型数据,可直接通过“:showtop(void)/专用于complex类型的showtop/显示栈顶的那一个complex型数据,它不可直接通过“”一次性输出!if(top=0)coutstackisempty!endl;elsecoutTop_Member:datatop-1.get_r(),“datatop-1.get_i()endl;,39,voidmain()stacks1;for(inti=1;is1c;complexc1(1.1,1.111),c2(2.2,2.222);s1c.push(c1);s1c.push(c2);/“压入”复数c2(处于栈顶)s1c.showtop();/调用专门补充的“特例函数”showtop,40,通过继承可以产生派生类。通过继承同样可产生派生的类模板。(1)一般类(其中不使用类型参数的类)作基类,派生出类模板(其中要使用类型参数)。classCB/CB为一般类(其中不使用类型参数),它将作为类模板CA的基类.;templateclassCA:publicCB/被派生出的CA为类模板,使用了类型参数T,其基类CB为一般类Tt;/私有数据为T类型的public:.;,9.3.3按照不同的方法派生类模板,41,(2)类模板作基类,派生出新的类模板。但仅基类中用到类型参数T(而派生的类模板中不使用T)。templateclassCB/CB为类模板(其中使用了类型参数T),它将作为类模板CA的基类Tt;/私有数据为T类型的public:Tgett()/用到类型参数Treturnt;.;templateclassCA:publicCB/CA为类模板,其基类CB也为类模板。注意,类型参数T/将被“传递”给基类CB,本派生类中并不使用该类型参数Tdoublet1;/私有数据成员public:.;/基类的名字应为实例化后的“CB”而并非仅使用“CB”。例如,在本例的派生类说明中,要对基类进行指定时必须使用“CB”而不可只使用“CB”:,42,(3)类模板作基类,派生出新的类模板,且基类与派生类中均使用同一个类型参数T。templateclassCB/CB为类模板(其中使用了类型参数T),它将作为类模板CA的基类Tt;/数据成员为T类型的public:Tgett()/用到类型参数Treturnt;.;templateclassCA:publicCB/CA为类模板,其基类CB也为类模板。注意,类型参数T将被“传递”给基类CB;本派生类中也将使用这同一个类型参数TTt1;/数据为T类型的public:.;,43,(4)类模板作基类,派生出新的类模板,但基类中使用类型参数T2,而派生类中使用另一个类型参数T1(而不使用T2)。templateclassCB/CB为类模板(其中使用了类型参数T2),它将作为类模板CA的基类T2t2;/数据为T2类型的public:.;templateclassCA:publicCB/CA为类模板,其基类CB也为类模板。注意,类型参数T2将被“传递”给基类CB;本派生类中还将使用另一个类型参数T1T1t1;/数据为T1类型的public:.;,9.3.3按照不同的方法派生类模板,44,9.4程序实例-设计一个链表

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论