南开大学C++课件第9章模板及其应用

上传人:抢*** 文档编号:243023160 上传时间:2024-09-14 格式:PPT 页数:49 大小:1.05MB
返回 下载 相关 举报
南开大学C++课件第9章模板及其应用_第1页
第1页 / 共49页
南开大学C++课件第9章模板及其应用_第2页
第2页 / 共49页
南开大学C++课件第9章模板及其应用_第3页
第3页 / 共49页
点击查看更多>>
资源描述
,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,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,int,max,(int a, int b) ,if(ab),return a;,else,return b;,double,max,(double a, double b) ,if(ab),return a;,else,return b;,char,max,(char a, char b) ,.,.,4,实际上,若,“,提取,”,出一个可变化的类型参数,T,,则可,“,综合,”,成为如下的同一个,函数(模板),,它实际上代表着一组函数:,T,max,(T a, T b),if(ab),return a;,else,return b;,在,C+,中定义完整的函数模板,max,时,格式如下:,template ,T max (T a, T b) ,if(ab),return a;,else,return b;,5,函数模板定义的一般格式为:,template ,返回类型 函数模板名 ( 形参表 ) 函数体 ,注意:,1),应在,“,返回类型,”,或,“,形参表,”,或,“,函数体,”,中使用上述的,“,类型形参名,”,。,2),调用处则类似于一般函数,用户只需给出具体的实参。,3),模板函数调用时,不进行实参到形参类型的自动转换。,6,9.1.2 函数模板的应用举例,- 参看书,p302,1. 函数模板例1,定义一个函数模板,max,,而后对它进行不同的调用。,#,include ,template T max (T a, T b),if(ab),return a;,else,return b;,7,void main() ,int i1=-11, i2=0;,double d1, d2;,cout,max(i1,i2),endl;,/,由实参,i1,i2,,系统可确定“类型形参,T”,对应于,int,cout,max(23,-56),endl;,cout,max(f, k),d1d2;,cout,max(d1,d2),endl;,/coutmax(23,-5.6) = ,max(23,-5.6), max(i1,i2) = 0,max(23,-56) = 23,char c1=T, c2=F; = max(c1,c2) = T,max(f, k) = k,input double d1, d2 :,123.45 99.67,d1=123.45, d2=99.67 = max(d1,d2) = 123.45,2.,函数模板例2 - 函数模板与函数重载,定义一个函数模板与一个函数,它们都叫做,min,C+,允许这种函数模板与函数同名的所谓重载使用方法。但注意,在这种情况下,每当遇见函数调用时,,C+,编译器都将,首先检查是否存在重载函数,,若匹配成功则调用该函数,否则,再去匹配函数模板,。,9,#include ,#include ,template type min (type a, type b),/type,型的,a,与,b,要能够进行“”比较运算!,return (ab?a:b);,char* min (char* a, char* b),/,函数,min,,字符串型参数,不能直接使用“”来进行比较,return (strcmp(a,b)0?a:b);,void main() ,coutmin(3,-10)endl;,/,使用函数模板,coutmin(2.5,99.5)endl;,coutmin(m,c)endl;,char* str1=The C program, * str2=The C+ program;,coutmin(str1, str2)endl;,/,使用重载函数!,10,3.,函数模板例3 - 二函数模板重载,定义两个函数模板,它们都叫做,sum,,都使用了一个类型参数,Type,,但两者的形参个数不同,,C+,允许使用这种函数模板重载的方法。,注意,参数表中允许出现与类型形参,Type,无关的其它类型的参数,如,“,int size,”,。,#include ,template Type sum (Type * array, int size ),/,求,array,数组前,size,个元素之和,Type total=0;,for (int i=0;isize;i+),total+=*(array+i);,return total;,11,template Type sum (Type * a1, Type * a2, int size ),/,求,a1,数组与,a2,数组前,size,个元素之和,Type total=0;,for (int i=0;isize;i+),total+=a1i+a2i;,return total;,void main() ,int a110,a28;,float af10;,.,/,为数组分量定值,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 ,#include ,template class Queue ,int Maxsize;,/,队列的大小,int front,rear;,/,元素放在,queuefront+1,到,queuerear,之中,keytype *queue;,/,动态数组,queue,,用来存放队列数据,public:,Queue (int size) ,/,构造函数,生成动态数组来存放队列数据,Maxsize=size;,queue=new keytypeMaxsize;,front=rear=-1;,/,意味着队列为空,;,15,int IsFull () ,if (rear=Maxsize-1),return 1;,else,return 0;,;,int IsEmpty () ,if (front=rear),return 1;,else,return 0;,;,void Add(const keytype ,keytype Delete(void);,;,16,/,Delete,在类体外定义,函数名前要加类限定符“,Queue:”,template keytype Queue:Delete(void),if (IsEmpty(),cout the queue is emptyendl;,exit (0);,return queue +front;,/Add,在类体外定义,template void Queue:Add(const keytype & item),if (IsFull(),cout the queue is fullendl;,else,queue+rear=item;,;,17,void main() ,int i=0; Queue Qi(10);,Queue Qf1(10),Qf2(10);,while (!Qi.IsFull() ,/Qi,中只能盛10个数,Qi.Add(2*i+);,/Qi,中: 0,2,4,6,8,10,12,14,16,18,Qf1.Add(3.0*i);,/Qf1,中: 3,6,9,12,15,18,21,24,27,30,for (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,.,程序执行后的显示结果如下:,0,1.5,9,3,18,9.2.,2,类模板说明,利用类模板(带类型参数或普通参数的类),一次就可定义出具有共性的一组类。,即,可使得所定义类中的某些数据成员、某些成员函数的参数、某些成员函数的返回值都可以是任意类型的。,19,类模板定义格式如下:,template ,class,类模板名 带上述类型形参或普通形参名的类定义体 ,说明,类型形参,时,使用,“,class,类型形参名,”,的方式,说明,普通形参,时,使用,“, 普通形参名,”,的方式。,注意:,1),类定义体中应使用上述的,“,类型形参名,”,及,“,普通形参名,”,。,2),利用类模板说明类对象时,要随类模板名同时给出对应于类型形参或普通形参的具体实参(从而实例化为一个具体的类)。说明格式为:,类模板名 ,注意:,类型形参,的相应实参为,类型名,,而,普通形参,的相应实参必须为一个,常量,。,20,3),类模板的成员函数既可以在类体内进行说明(自动按内联函数处理),也可以在类体外进行说明。,在类体外说明(定义)时使用如下格式:,template ,返回类型 类模板名 :,函数名( 形参表 ) ,. /函数体,;,上述的,“,形参1的名字,”,来自于,“,形参1的说明,”,,由,“,甩掉,”,说明部分的,“,类型,”,而得,是对类型形参或普通形参的使用。而,“,类模板名 :,”,所起的作用正是在类体外定义成员函数时在函数名前所加的类限定符!,21,例如,对具有一个类型参数,T,的类模板,TestClass,,在类体外定义其成员函数,getData,时的大致样式如下:,template ,T TestClass:getData(,形参表 ) ,. /函数体,;,其中的,“,TestClass:,”,所起的作用正是在类体外定义成员函数时在函数名前所加的类限定符!,22,9.2.,3,使用类型参数和普通参数的类模板,1,仅使用类型参数的类模板,#,include ,template class TestClass ,public:,T buffer10;,/T,类型的数据成员,buffer,数组大小固定为10 (灵活性差!),T getData(int j);,/,获取,T,类型,buffer(,数组)的第,j,个分量,;,template ,T TestClass:getData(int j) ,return *(buffer+j);,;,23,void main() ,TestClass ClassInstA;,/char,取代,T,,从而实例化为一个具体的类,char cArr6=abcde;,for(int i=0; i5; i+),ClassInstA.bufferi=cArri;,for(i=0; i5; i+) ,char res=ClassInstA.getData(i);,coutres ;,coutendl;,24,TestClass ClassInstF;,/,实例化为另外一个具体的类,double fArr6=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+) ,double res=ClassInstF.getData(i);,coutres ;,coutendl;,程序执行后的显示结果如下:,a b c d e,2.1 13.2 24.3 35.4 46.5 57.6,25,2,仅使用普通参数(非类型参数)的类模板示例,#,include ,template class TestClass ,public:,int bufferi;,/,使,buffer,的大小可变化,但其类型则固定为,int(,灵活性差!),int getData(int j);,;,template ,int TestClass:getData(int j) ,return *(buffer+j);,;,26,void main() ,TestClass ClassInstF;,double fArr6=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+) ,double res=ClassInstF.getData(i);,coutres ;,coutendl;,程序执行后的显示结果如下:,2 13 24 35 46 57,27,3,既使用类型参数又使用 普通参数的类模板示例,#,include ,#include string.h,template class TestClass ,public:,T bufferi;,/T,类型的,buffer,,其大小随普通形参,i,的值变化(灵活性大!),T getData(int j);,;,template ,T TestClass:getData(int j) ,return *(buffer+j);,;,28,void main() ,TestClass ClassInstA;,char cArr6=abcde;,strcpy(ClassInstA.buffer, cArr);,for(int i=0; i5; i+) ,char res=ClassInstA.getData(i);,coutres ;,coutendl;,29,TestClass ClassInstF;,double fArr6=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+) ,double res=ClassInstF.getData(i);,coutres ;,coutendl;,程序执行后的显示结果如下:,a b c d e,2.1 13.2 24.3 35.4 46.5 57.6,30,9.3,关于类模板的若干问题说明,9.3.1,静态成员及友元,9.3.2,特例版本,9.3.3,按不同方法来派生类模板,31,1,类模板的静态成员,类模板也允许有静态成员。实际上,它们是类模板之实例化类的静态成员。也就是说,对于一个类模板的每一个实例化类,其所有的对象共享其静态成员。,例如:,templateclass C,static T t,;,/,类模板的静态成员,t,;,类模板的静态成员在模板定义时是不会被创建的,其创建是在类的实例化之后。如:,CAaiobj1, aiobj2,;,CAacobj1, acobj2,;,对象,aiobj1,和,aiobj2,将共享实例化类,CA,的静态成员,int t,,而对象,acobj1,,,acobj2,将共享实例化类,CA,的静态成员,char t,。,9.3.1,静态成员及友元,32,2,类模板的友元,类模板定义中允许包含友元。我们讨论类模板中的友元函数,因为说明一个友元类,实际上相当于说明该类的成员函数都是友元函数。, 该友元函数为一般函数,则它将是该类模板的所有实例化类的友元函数。, 该友元函数为一函数模板,但其类型参数与类模板的类型参数无关。则该函数模板的所有实例化(函数)都是类模板的所有实例化类的友元。, 更复杂的情形是,该友元函数为一函数模板,且它与类模板的类型参数有关。例如,函数模板可以用该类模板作为其函数参数的类型。在友元函数模板定义与相应类模板(的类型参数)有关时,该友元函数模板的实例有可能只是该类模板的某些特定实例化(而不是所有实例化)类的友元。,9.3.1,静态成员及友元,33,大多数类模板不能任意进行实例化。也就是说类模板的类型参数往往在实例化时不允许用任意的类(类型)作为,“,实参,”,。模板的,“,实参,”,不当,主要会在实例化后的函数成员调用中体现出来,例如,template class stack ,/,栈中元素类型为,T,的,stack,类模板,T num MAX;,/num,中存放栈的实际数据,int top;,/top,为栈顶位置,public:,stack () top=0; /,构造函数,void push (T a) numtop+=a; ,/,将数据,a,“,压入,”,栈顶,void showtop(),/,显示栈顶数据,/,模板中通用的,showtop,,显示栈顶的那一个,T,类型的数据,/,(必须为可直接通过运算符,“,”,来显示的数据,),if (top=0) cout stack is empty! endl;,else coutTop_Member:numtop-1endl;, ;,9.3.2,特例版本,34,在上面的类模板,stack,中,以下的实例化都是可行的:,stacki1,i2;,stackc1,c2;,stackf1,f2,;,等等。,但如果采用用户定义类型而又未在该类中对运算符,“,”,进行重载时,就会产生问题,例如:,stackcom1,com2;,由于在执行,com1.showtop(),函数时,将需要对,complex,类型的数据,numtop-1,通过使用运算符,“,”,来进行输出,而系统和用户都没有定义过这种操作,因此,类模板,stack,的实例化,stack,就是不可行的了,。,9.3.2,特例版本,35,如果用户在上述情况下,需要使,stack,可行,可有几个办法。, 对于类,complex,追加插入运算符,“,”,的重载定义;, 也可在类模板,stack,的定义中增加一个,“,特例版本,”,(也称,“,特殊版本,”,)的定义。例如在上例中,可以在类模板定义之后给出如下形式的特例版本:,void stack:showtop(),/,专用于,complex,类型的,showtop,(专门补充的,“,特例版本,”,),显示栈顶的,/,那一个,complex,型数据。其中的,stack,为一个实例化后的模板类。,if (top=0) cout stack is empty! endl; else,coutTop_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,实例,class complex /,复数类型,complex,double real, image;,public:,.,;,template ,class stack ,T data 20;,int top;,public:,void showtop(void); /,显示栈顶数据,.,;,38,template void stack:,showtop,(void) /,通用的,showtop,/(T,类型数据,可直接通过“”来一次性输出的数据),if (top=0),cout stack is empty! endl;,else,coutTop_Member:datatop-1endl;,void stack:,showtop,(void) /,专用于,complex,类型的,showtop,/,显示栈顶的那一个,complex,型数据,它不可直接通过“”一次性输出!,if (top=0),cout stack is empty! endl;,else,coutTop_Member:datatop-1.get_r(), “,datatop-1.get_i()endl;,39,void main() ,stack s1;,for (int i=1; i=6; i+),s1.push(2*i); /“,压入”:2,4,6,8,10,12 (栈顶为12),s1.showtop(); /,调用模板中通用的,showtop,stack s1c;,complex c1(1.1, 1.111), c2(2.2, 2.222);,s1c.push(c1);,s1c.push(c2);/“,压入”复数,c2 (,处于栈顶),s1c.showtop(); /,调用专门补充的“特例函数”,showtop,40,通过继承可以产生派生类。通过继承同样可产生派生的类模板。,(,1,)一般类(其中不使用类型参数的类)作基类,派生出类模板(其中要使用类型参数)。,class CB ,/CB,为一般类(其中不使用类型参数),它将作为类模板,CA,的基类,.,;template class CA:public CB ,/,被派生出的,CA,为类模板,使用了类型参数,T,,其基类,CB,为一般类,T t;,/,私有数据为,T,类型的,public,:,.,;,9.3.3,按照不同的方法派生类模板,41,(,2,)类模板作基类,派生出新的类模板。但仅基类中用到类型参数,T,(而派生的类模板中不使用,T,)。,template class CB /CB,为类模板(其中使用了类型参数,T,),它将作为类模板,CA,的基类,T t; /,私有数据为,T,类型的,public:,T gett() /,用到类型参数,T return t; ,.,;,template class CA:public CB ,/CA,为类模板,其基类,CB,也为类模板。注意,类型参数,T,/,将被,“,传递,”,给基类,CB,,本派生类中并不使用该类型参数,T,double t1; /,私有数据成员,public:,. ; /,基类的名字应为实例化后的,“,CB,”,而并非仅使用,“,CB,”,。例如,在本例的派生类说明中,要对基类进行指定时必须使用,“,CB,”,而不可只使用,“,CB,”,:,42,(,3,)类模板作基类,派生出新的类模板,且基类与派生类中均使用同一个类型参数,T,。,template class CB ,/CB,为类模板(其中使用了类型参数,T,),它将作为类模板,CA,的基类,T t; /,数据成员为,T,类型的,public:,T gett() /,用到类型参数,T,return t;,.,;,template class CA:public CB /CA,为类模板,其基类,CB,也为类模板。注意,类型参数,T,将被,“,传递,”,给基类,CB,;本派生类中也将使用这同一个类型参数,T,T t1; /,数据为,T,类型的,public: .;,43,(,4,)类模板作基类,派生出新的类模板,但基类中使用类型参数,T2,,而派生类中使用另一个类型参数,T1,(而不使用,T2,)。,template class CB ,/CB,为类模板(其中使用了类型参数,T2,),它将作为类模板,CA,的基类,T2 t2; /,数据为,T2,类型的,public:,.,;,template class CA:public CB /CA,为类模板,其基类,CB,也为类模板。注意,类型参数,T2,将被,“,传递,”,给基类,CB,;本派生类中还将使用另一个类型参数,T1,T1 t1; /,数据为,T1,类型的,public:,.,;,9.3.3,按照不同的方法派生类模板,44,9,.4,程序实例,-,设计一个链表类模板,- 参看书,p318,定义一个处理链表的类模板,list,,它含有一个类型形参,T,,以指出每一链表项的,data,数据域的类型。,#include ,#include ,45,template class list ,struct node ,T data;,node * next;, *,head, *,tail,;,/*,数据成员,head,与,tail,均为指针,。其中的,head,总指向链表的首项,而,tail,总指向链表的尾项。每当准备往链表中加入一个表项(及其表项,data,数据)时,程序中首先使用“,new node”,来动态生成一个新的表项空间,并“填入”该表项的,data,数据,而后通过指针的改变与关联,将该表项加入到以,head,为首以,tail,为尾的当前链表结构中(以形成一个更新后的链表)。,*/,46,public:,list,() /,构造函数,创建一个“空链表”,head=tail=NULL;,;,void,Insert,(T * item) ,/,动态生成链表项空间,并将,item,所指向的,T,型数据放至该项的,data;,/,而后将新生成的该链表项插入到原链的链首(链表的“栈”式用法)。,.,;,void,Append,(T * item),/,动态生成链表项空间,并将,item,所指向的,T,型数据放入该项的,data;,/,而后将新生成的该项附加到原链的链尾(链表的“队列”式用法)。,.,;,T,get,() ,/,取出链表首项的数据(,data,域值),并将该首项从链表中删去,.,;,; /类模板,list,定义结束,47,class person,public:,char name20;,int age;,float hight;,;,/*,注:若说明为“,char* name;”,,则主函数处要通过,new,为每一对象的,name,域申请动态空间! */,void main() ,person ps;,list link1;,list link2;,cout - Input 5 persons information -endl;,for (int i=0;i 0 - 1 - 2 - 3 - 4,link2,链表:,head - 4,号人员信息 - 3号人员信息 - 2号人员信息 - 1号人员信息 - 0号人员信息,*/,cout - The result -endl;,for (i=0;i5;i+) ,ps=link2.get(); /,取出,link2,链表首项的人员信息,link2.Append(,/,将刚从,link2,首取来的人员信息,,/再一次附加到,link2,链表的链尾,coutps.name link1.get()endl;,/,输出,link2,链表人员信息的,name,,/,以及,link1,链表表项中的对象的顺序号,第九章 结束,
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 图纸专区 > 小学资料


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!