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

上传人:re****.1 文档编号:567969065 上传时间:2024-07-22 格式:PPT 页数:50 大小:946.51KB
返回 下载 相关 举报
南开大学C++课件 第9章 模板及其应用_第1页
第1页 / 共50页
南开大学C++课件 第9章 模板及其应用_第2页
第2页 / 共50页
南开大学C++课件 第9章 模板及其应用_第3页
第3页 / 共50页
南开大学C++课件 第9章 模板及其应用_第4页
第4页 / 共50页
南开大学C++课件 第9章 模板及其应用_第5页
第5页 / 共50页
点击查看更多>>
资源描述

《南开大学C++课件 第9章 模板及其应用》由会员分享,可在线阅读,更多相关《南开大学C++课件 第9章 模板及其应用(50页珍藏版)》请在金锄头文库上搜索。

1、第第9 9章章 模板及其应用模板及其应用9.1 9.1 函数模板函数模板9.2 9.2 类模板类模板9.3 9.3 关于类模板若干问题的说明关于类模板若干问题的说明 9.4 9.4 程序实例程序实例 本本章章介介绍绍函函数数模模板板与与类类模模板板的的定定义义及及其其使使用用方方法法。通通过过使使用用模模板板,可可使使所所编编程程序序更更加加紧紧凑凑,增加程序的通用性及可重用性。增加程序的通用性及可重用性。1 9.1 9.1 函数模板函数模板9.1.1 9.1.1 函数模板的概念及说明函数模板的概念及说明9.1.2 9.1.2 函数模板的应用举例函数模板的应用举例-9.1.1 9.1.1 函数

2、模板的概念及说明函数模板的概念及说明 - - 参看书参看书p299-301p299-301 通通常常设设计计的的算算法法(处处理理语语句句)是是可可以以处处理理多多种种数数据据类类型型的的,但但目目前前处处理理相相同同的的问问题题,仍要分别定义多个类似的函数。仍要分别定义多个类似的函数。 2 intmax(inta,intb)if(ab)returna;elsereturnb;doublemax(doublea,doubleb)if(ab)returna;elsereturnb;charmax(chara,charb).3 实际上,若实际上,若“提取提取”出一个可变化的类型参数出一个可变化的类

3、型参数T T,则可则可“综综合合”成为如下的同一个成为如下的同一个函数(模板),函数(模板),它实际上代表着一组函它实际上代表着一组函数:数: T T maxmax (T a, T b) (T a, T b) if(ab)if(ab) return a; return a;elseelse return b; return b; 在在C+C+中定义完整的函数模板中定义完整的函数模板maxmax时,格式如下:时,格式如下:template template T max (T a, T b) T max (T a, T b) if(ab) if(ab) return a; return a; el

4、se else return b; return b; 4函数模板定义的一般格式为:函数模板定义的一般格式为:template 返回类型返回类型 函数模板名函数模板名 ( ( 形参表形参表 ) ) 函数体函数体 注意注意: : 1)1) 应应在在“返返回回类类型型”或或“形形参参表表”或或“函函数数体体”中中使使用上述的用上述的“类型形参名类型形参名” ” 。 2)2) 调调用用处处则则类类似似于于一一般般函函数数,用用户户只只需需给给出出具具体体的的实实参。参。 3)3) 模模板板函函数数调调用用时时,不不进进行行实实参参到到形形参参类类型型的的自自动动转转换。换。 59.1.2 9.1.2

5、 函数模板的应用举例函数模板的应用举例 - - 参看书参看书p302p3021. 1. 函数模板例函数模板例1 1定义一个函数模板定义一个函数模板maxmax,而后对它进行不同的调用。而后对它进行不同的调用。# #include include template T max (T a, T b) template T max (T a, T b) if(ab) if(ab) return a; return a; else else return b; return b; 6 void main() void main() intint i1=-11, i2=0; i1=-11, i2=0;

6、double d1, d2; double d1, d2; coutcoutmax(i1,i2)max(i1,i2)endlendl; ; /由实参由实参i1,i2,系统可确定系统可确定“类型形参类型形参T”对应于对应于int coutcoutmax(23,-56)max(23,-56)endlendl; ; coutcoutmax(f, k)max(f, k)d1d2;d1d2; coutcoutmax(d1,d2)max(d1,d2)endlendl; ; / /coutcoutmax(23,-5.6) = max(23,-5.6) = max(23,-5.6)max(23,-5.6) m

7、ax(i1,i2) = 0 i1=-11, i2=0; = max(i1,i2) = 0max(23,-56) = 23max(23,-56) = 23char c1=T, c2=F; = max(c1,c2) = Tchar c1=T, c2=F; = max(c1,c2) = Tmax(f, k) = kmax(f, k) = kinput double d1, d2 : input double d1, d2 : 123.45 99.67123.45 99.67d1=123.45, d2=99.67 = max(d1,d2) = 123.45d1=123.45, d2=99.67 = m

8、ax(d1,d2) = 123.45 2. 2. 函数模板例函数模板例2 - 2 - 函数模板与函数重载函数模板与函数重载 定定义义一一个个函函数数模模板板与与一一个个函函数数,它它们们都都叫叫做做minmin,C+C+允允许许这这种种函函数数模模板板与与函函数数同同名名的的所所谓谓重重载载使使用用方方法法。但但注注意意,在在这这种种情情况况下下,每每当当遇遇见见函函数数调调用用时时,C+C+编编译译器器都都将将首首先先检检查查是是否否存存在在重重载载函函数数,若若匹匹配配成成功功则则调调用用该该函函数数,否则否则再去匹配函数模板再去匹配函数模板。 8 #include#includetemp

9、latetypemin(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(st

10、r1,str2)endl;/使用重载函数使用重载函数!9 3. 3. 函数模板例函数模板例3 - 3 - 二函数模板重载二函数模板重载 定定义义两两个个函函数数模模板板,它它们们都都叫叫做做sumsum,都都使使用用了了一一个个类类型型参参数数TypeType,但但两两者者的的形形参参个个数数不不同同,C+C+允允许许使使用用这这种种函函数数模模板重载的方法。板重载的方法。 注注意意,参参数数表表中中允允许许出出现现与与类类型型形形参参TypeType无无关关的的其其它它类类型的参数,如型的参数,如“intint size” size”。#includetemplateTypesum(Type

11、*array,intsize)/求求array数组前数组前size个元素之和个元素之和Typetotal=0;for(inti=0;isize;i+)total+=*(array+i);returntotal;10templateTypesum(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

12、)endl;/求出求出a1数组前数组前10个元素之和并输出个元素之和并输出coutsum(af,10)endl;coutsum(a1,a2,8)endl;/求求a1与与a2数组前数组前8个元素之和并输出个元素之和并输出11 9.2 9.2 类模板类模板9.2.1 9.2.1 一个队列类模板一个队列类模板 9.2.2 9.2.2 类模板说明类模板说明9.2.9.2.3 3 使用类型参数和普通参数的类模板使用类型参数和普通参数的类模板 129.3.1 9.3.1 设计一个队列类模板设计一个队列类模板 - - 参看书参看书p305p305 队列与栈不同,对数据采用队列与栈不同,对数据采用“先进先出先

13、进先出”-”-FIFOFIFO的管理的管理方式(而栈则使用方式(而栈则使用“先进后出先进后出”-”-FILOFILO方式)。方式)。 队列数据放于作为类成员的动态数组队列数据放于作为类成员的动态数组queuequeue之中,在构造之中,在构造函数中,将通过函数中,将通过newnew来生成该动态数组,动态数组来生成该动态数组,动态数组queuequeue的大的大小由类的私有数据成员小由类的私有数据成员MaxsizeMaxsize之值来确定。但注意,此示例之值来确定。但注意,此示例并没有循环使用上述的动态数组并没有循环使用上述的动态数组queuequeue空间。即是说,队列中空间。即是说,队列中至

14、多可以存放至多可以存放MaxsizeMaxsize个数据项,即使取走若干项后有了空闲个数据项,即使取走若干项后有了空闲空间后也不可重新进行使用。若稍加改造,使存取数据时首空间后也不可重新进行使用。若稍加改造,使存取数据时首先通过对下标进行模先通过对下标进行模MaxsizeMaxsize的运算,则可实现循环使用动态的运算,则可实现循环使用动态数组数组queuequeue空间的功能,我们把它留作一个练习。空间的功能,我们把它留作一个练习。 13 #include#includetemplateclassQueueintMaxsize;/队列的大小队列的大小intfront,rear;/元素放在元素

15、放在queuefront+1到到queuerear之中之中keytype*queue;/动态数组动态数组queue,用来存放队列数据用来存放队列数据public:Queue(intsize)/构造函数,生成动态数组来存放队列数据构造函数,生成动态数组来存放队列数据Maxsize=size;queue=newkeytypeMaxsize;front=rear=-1;/意味着队列为空意味着队列为空;14intIsFull()if(rear=Maxsize-1)return1;elsereturn0;intIsEmpty()if(front=rear)return1;elsereturn0;void

16、Add(constkeytype&);keytypeDelete(void);15/Delete在类体外定义,函数名前要加类限定符在类体外定义,函数名前要加类限定符“Queue:”templatekeytypeQueue:Delete(void)if(IsEmpty()coutthequeueisemptyendl;exit(0);returnqueue+front;/Add在类体外定义在类体外定义templatevoidQueue:Add(constkeytype&item)if(IsFull()coutthequeueisfullendl;elsequeue+rear=item;16voi

17、dmain()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首删取一元素,乘以

18、首删取一元素,乘以4.5,而后将其加入到,而后将其加入到Qf2尾部尾部/四次循环往四次循环往Qf2队列尾加入:队列尾加入:0*4.5,2*4.5,4*4.5,6*4.5.程序执行后的显示结果如下:程序执行后的显示结果如下:01.59 317 9.2. 9.2.2 2 类模板说明类模板说明 利利用用类类模模板板(带带类类型型参参数数或或普普通通参参数数的类),一次就可定义出具有共性的一组类。的类),一次就可定义出具有共性的一组类。 即即,可可使使得得所所定定义义类类中中的的某某些些数数据据成成员员、某某些些成成员员函函数数的的参参数数、某某些些成成员员函函数数的的返回值都可以是任意类型的。返回值

19、都可以是任意类型的。 18 类模板定义格式如下:类模板定义格式如下: template template class class 类类模模板板名名 带带上上述述类类型型形形参参或或普普通通形形参参名名的的类类定定义义体体 说说明明类类型型形形参参时时,使使用用“class class 类类型型形形参参名名”的的方方式式,说说明明普通形参普通形参时,使用时,使用“ 普通形参名普通形参名”的方式。的方式。 注意注意: : 1)1) 类类定定义义体体中中应应使使用用上上述述的的“类类型型形形参参名名”及及“普普通通形形参参名名”。2)2) 利利用用类类模模板板说说明明类类对对象象时时,要要随随类类模

20、模板板名名同同时时给给出出对对应应于于类类型型形形参参或或普普通通形形参参的的具具体体实实参参(从从而而实实例例化化为为一一个个具具体体的的类)。说明格式为:类)。说明格式为: 类模板名类模板名 注注意意:类类型型形形参参的的相相应应实实参参为为类类型型名名,而而普普通通形形参参的的相相应应实参必须为一个实参必须为一个常量常量。 19 3)3) 类模板的成员函数既可以在类体内进行说明(自动类模板的成员函数既可以在类体内进行说明(自动按内联函数处理),也可以在类体外进行说明。按内联函数处理),也可以在类体外进行说明。 在类体外说明(定义)时使用如下格式:在类体外说明(定义)时使用如下格式: te

21、mplate template 返回类型返回类型 类模板名类模板名 : :函数名函数名( ( 形参表形参表 ) ) . / . /函数体函数体 ; 上述的上述的“形参形参1 1的名字的名字”来自于来自于“形参形参1 1的说明的说明”,由,由“甩甩掉掉”说明部分的说明部分的“类型类型”而得,是对类型形参或普通形参的而得,是对类型形参或普通形参的使用。而使用。而 “ “类模板名类模板名 : :”所所起的作用正是在类体外定义成员函数时在函数名前所加的类起的作用正是在类体外定义成员函数时在函数名前所加的类限定符限定符! !20 例例 如如 , 对对 具具 有有 一一 个个 类类 型型 参参 数数 T

22、T的的 类类 模模 板板TestClassTestClass,在在类类体体外外定定义义其其成成员员函函数数getDatagetData时时的的大致样式如下:大致样式如下: template template T T TestClassTestClass:getDatagetData( ( 形参表形参表 ) ) . / . /函数体函数体 ; ; 其其中中的的“TestClassTestClass:”所所起起的的作作用用正正是是在在类体外定义成员函数时在函数名前所加的类限定符类体外定义成员函数时在函数名前所加的类限定符! ! 219.2.9.2.3 3使用类型参数和普通参数的类模板使用类型参数和

23、普通参数的类模板1 1 仅使用类型参数的类模板仅使用类型参数的类模板#includetemplateclassTestClasspublic:Tbuffer10;/T类型的数据成员类型的数据成员buffer数组大小固定为数组大小固定为10(灵活性差灵活性差!)TgetData(intj);/获取获取T类型类型buffer(数组数组)的第的第j个分量个分量;templateTTestClass:getData(intj)return*(buffer+j);22 voidmain()TestClassClassInstA;/char取代取代T,从而实例化为一个具体的类从而实例化为一个具体的类cha

24、rcArr6=abcde;for(inti=0;i5;i+)ClassInstA.bufferi=cArri;for(i=0;i5;i+)charres=ClassInstA.getData(i);coutres;coutendl;23TestClassClassInstF;/实例化为另外一个具体的类实例化为另外一个具体的类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

25、;coutendl;程序执行后的显示结果如下:程序执行后的显示结果如下:abcde2.113.224.335.446.557.6242仅使用普通参数仅使用普通参数(非类型参数非类型参数)的类模板示例的类模板示例#includetemplateclassTestClasspublic:intbufferi;/使使buffer的大小可变化,但其类型则固定为的大小可变化,但其类型则固定为int(灵活性差灵活性差!)intgetData(intj);templateintTestClass:getData(intj)return*(buffer+j);25voidmain()TestClassClas

26、sInstF;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;程序执行后的显示结果如下:程序执行后的显示结果如下:2132435465726 3 3 既使用类型参数又使用既使用类型参数又使用 普通参数的类模板示例普通参数的类模板示例#include#includestring.htemplateclassTestClasspublic:Tbufferi

27、;/T类型的类型的buffer,其大小随普通形参其大小随普通形参i的值变化的值变化(灵活性大灵活性大!)TgetData(intj);templateTTestClass:getData(intj)return*(buffer+j);27voidmain()TestClassClassInstA;charcArr6=abcde;strcpy(ClassInstA.buffer,cArr);for(inti=0;i5;i+)charres=ClassInstA.getData(i);coutres;coutendl;28TestClassClassInstF;doublefArr6=12.1,2

28、3.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.629 9.3 9.3 关于类模板的若干问题说明关于类模板的若干问题说明 9.3.1 9.3.1 静态成员及友元静态成员及友元9.3.2 9.3.2 特例版本特例版本9.3.3 9.3.3 按不同方法来派生类模板按不同方法来派生类模板3

29、0 1 1类模板的静态成员类模板的静态成员n类模板也允许有静态成员。实际上,它们是类模板之实例化类的静态成类模板也允许有静态成员。实际上,它们是类模板之实例化类的静态成员。也就是说,对于一个类模板的每一个实例化类,其所有的对象共享员。也就是说,对于一个类模板的每一个实例化类,其所有的对象共享其静态成员。其静态成员。例如:例如:templateclass Ctemplateclass C static T t static T t; /类模板的静态成员类模板的静态成员t t ; ;类模板的静态成员在模板定义时是不会被创建的,其创建是在类的实例化之类模板的静态成员在模板定义时是不会被创建的,其创建

30、是在类的实例化之后。如:后。如: CA CAaiobj1, aiobj2aiobj1, aiobj2; CAacobj1, acobj2CAacobj1, acobj2; 对象对象 aiobj1 aiobj1 和和 aiobj2 aiobj2 将共享实例化类将共享实例化类 CACA 的静态成员的静态成员 intint t t ,而,而对象对象acobj1acobj1,acobj2 acobj2 将共享实例化类将共享实例化类CACA的静态成员的静态成员 char tchar t。 9.3.1 9.3.1 静态成员及友元静态成员及友元31 2 2类模板的友元类模板的友元类模板定义中允许包含友元。我

31、们讨论类模板中的友元函数,因为说类模板定义中允许包含友元。我们讨论类模板中的友元函数,因为说明一个友元类,实际上相当于说明该类的成员函数都是友元函数。明一个友元类,实际上相当于说明该类的成员函数都是友元函数。n 该友元函数为一般函数,则它将是该类模板的所有实例化类的友该友元函数为一般函数,则它将是该类模板的所有实例化类的友元函数。元函数。n 该友元函数为一函数模板,但其类型参数与类模板的类型参数无该友元函数为一函数模板,但其类型参数与类模板的类型参数无关。则该函数模板的所有实例化(函数)都是类模板的所有实例化类关。则该函数模板的所有实例化(函数)都是类模板的所有实例化类的友元。的友元。n 更复

32、杂的情形是,该友元函数为一函数模板,且它与类模板的类更复杂的情形是,该友元函数为一函数模板,且它与类模板的类型参数有关。例如,函数模板可以用该类模板作为其函数参数的类型。型参数有关。例如,函数模板可以用该类模板作为其函数参数的类型。在友元函数模板定义与相应类模板(的类型参数)有关时,该友元函在友元函数模板定义与相应类模板(的类型参数)有关时,该友元函数模板的实例有可能只是该类模板的某些特定实例化(而不是所有实数模板的实例有可能只是该类模板的某些特定实例化(而不是所有实例化)类的友元。例化)类的友元。 9.3.1 9.3.1 静态成员及友元静态成员及友元32 大多数类模板不能任意进行实例化。也就

33、是说类模板的类型参数往往在实大多数类模板不能任意进行实例化。也就是说类模板的类型参数往往在实例化时不允许用任意的类(类型)作为例化时不允许用任意的类(类型)作为“实参实参”。模板的。模板的“实参实参”不不当,主要会在实例化后的函数成员调用中体现出来,例如当,主要会在实例化后的函数成员调用中体现出来,例如 template class stack template class stack /栈中元素类型为栈中元素类型为T T 的的stack stack 类模类模板板T num MAX; T num MAX; /num /num 中存放栈的实际数据中存放栈的实际数据intint top; top;

34、 /top /top 为栈顶位置为栈顶位置 public: public: stack () top=0; /stack () top=0; /构造函数构造函数void push (T a) void push (T a) numtopnumtop+=a; +=a; /将数据将数据a“a“压入压入”栈顶栈顶void void showtopshowtop() () / / 显示栈顶数据显示栈顶数据/模板中通用的模板中通用的showtopshowtop,显示栈顶的那一个,显示栈顶的那一个T T 类型的数据类型的数据/(必须为(必须为可直接通过运算符可直接通过运算符“”来显示的数据来显示的数据)i

35、f (top=0) if (top=0) coutcout stack is empty! stack is empty! endlendl; ; else else coutcoutTop_MemberTop_Member:numtop-1:numtop-1endlendl; ; ; ; 9.3.2 9.3.2 特例版本特例版本 33 在上面的类模板在上面的类模板stack stack 中,以下的实例化都是可行的:中,以下的实例化都是可行的: stackstacki1,i2; i1,i2; stackc1,c2; stackc1,c2; stackf1,f2stackf1,f2; ; 等等。

36、等等。但如果采用用户定义类型而又未在该类中对运算符但如果采用用户定义类型而又未在该类中对运算符“”进行重载时,就会产生问题,例如:进行重载时,就会产生问题,例如:stackcom1,com2;stackcom1,com2; 由于在执行由于在执行com1.showtop() com1.showtop() 函数时,将需要对函数时,将需要对complex complex 类类型的数据型的数据numtop-1 numtop-1 通过使用运算符通过使用运算符“”来进行输出,来进行输出,而系统和用户都没有定义过这种操作,因此,类模板而系统和用户都没有定义过这种操作,因此,类模板stack stack 的实

37、例化的实例化stackstack就是不可行的了就是不可行的了。 9.3.2 9.3.2 特例版本特例版本 34 如果用户在上述情况下,需要使如果用户在上述情况下,需要使stackstack可行,可可行,可有几个办法。有几个办法。n 对于类对于类complex complex 追加插入运算符追加插入运算符“”的重载定义;的重载定义;n 也可在类模板也可在类模板stack stack 的定义中增加一个的定义中增加一个“特例版本特例版本”(也称(也称“特殊版本特殊版本”)的定义。例如在上例中,可以在)的定义。例如在上例中,可以在类模板定义之后给出如下形式的特例版本:类模板定义之后给出如下形式的特例版

38、本:void stack:void stack:showtopshowtop() () /专用于专用于complex complex 类类型的型的showtopshowtop(专门补充的(专门补充的“特例版本特例版本”),显示栈顶的),显示栈顶的/那一个那一个complex complex 型数据。其中的型数据。其中的stackstack为一个实为一个实例化后的模板类。例化后的模板类。if (top=0) if (top=0) coutcout stack is empty! stack is empty! endlendl; else ; else coutcoutTop_MemberTop

39、_Member:numtop-1.get_r(), :numtop-1.get_r(), numtop-1.get_i()numtop-1.get_i()endlendl; ; 9.3.2 9.3.2 特例版本特例版本 35 假设自定义的复数类型假设自定义的复数类型complex complex 中具有公有的成员函数中具有公有的成员函数get_rget_r()()以及以及get_iget_i()(),用于获取复数的实部和虚部。如此,当实,用于获取复数的实部和虚部。如此,当实例化例化stackstack时将按该特例版本的定义进行。时将按该特例版本的定义进行。概括地说,当处理某一类模板中的可变类型

40、概括地说,当处理某一类模板中的可变类型T T型数据时,如型数据时,如果处理算法并不能对所有的果处理算法并不能对所有的T T类型取值做统一的处理,此时类型取值做统一的处理,此时可通过使用专门补充的所谓特例版本来对具有特殊性的那可通过使用专门补充的所谓特例版本来对具有特殊性的那些些T T类型取值做特殊处理。类型取值做特殊处理。n 也可以对函数模板,或类模板的个别函数成员补充其也可以对函数模板,或类模板的个别函数成员补充其“特例版本特例版本”定义。定义。例如,可将该例的例如,可将该例的showtopshowtop功能进一步划分,让功能进一步划分,让showtopshowtop调调用另一个新增加的用另

41、一个新增加的showshow函数,而由函数,而由showshow函数具体考虑对两函数具体考虑对两种情况的处理:一种处理可直接通过运算符种情况的处理:一种处理可直接通过运算符“”来显示来显示的数据,另一种的数据,另一种“特例版本特例版本”专用于处理专用于处理complexcomplex类型的数类型的数据。据。 9.3.2 9.3.2 特例版本特例版本 36实例实例class complex class complex /复数类型复数类型complexcomplexdouble real, image;double real, image;public:public:.;template temp

42、late class stack class stack T data 20; T data 20; intint top; top;public: public: void void showtop(voidshowtop(void); /); /显示栈顶数据显示栈顶数据 . .; 37templatevoidstack:showtop(void) /通用的通用的showtop/(T类型数据,可直接通过类型数据,可直接通过“”来一次性输出的数据)来一次性输出的数据)if(top=0)coutstackisempty!endl;elsecoutTop_Member:datatop-1endl;

43、voidstack:showtop(void)/专用专用于于complex类型的类型的showtop/显示栈顶的那一个显示栈顶的那一个complex型数据,它不可直接通过型数据,它不可直接通过“”一次性输出一次性输出!if(top=0)coutstackisempty!endl;elsecoutTop_Member:datatop-1.get_r(),“datatop-1.get_i()endl;38voidmain()stacks1;for(inti=1;i=6;i+)s1.push(2*i);/“压入压入”:2,4,6,8,10,12(栈顶为栈顶为12)s1.showtop();/调用模板

44、中通用的调用模板中通用的showtopstacks1c;complexc1(1.1,1.111),c2(2.2,2.222);s1c.push(c1);s1c.push(c2);/“压入压入”复数复数c2(处于栈顶处于栈顶)s1c.showtop();/调用专门补充的调用专门补充的“特例函数特例函数”showtop39 通过继承可以产生派生类。通过继承同样可产生派生的类通过继承可以产生派生类。通过继承同样可产生派生的类模板。模板。 n(1 1)一般类(其中不使用类型参数的类)作基类,派生出)一般类(其中不使用类型参数的类)作基类,派生出类模板(其中要使用类型参数)。类模板(其中要使用类型参数)

45、。class CB class CB /CB /CB 为一般类(其中不使用类型参数),它为一般类(其中不使用类型参数),它将作为类模板将作为类模板CA CA 的基类的基类. . ;template class template class CA:publicCA:public CB CB /被派生出的被派生出的CA CA 为类模板,使用了类型参数为类模板,使用了类型参数T T,其基类,其基类CB CB 为一般类为一般类T t; T t; /私有数据为私有数据为T T 类型的类型的 publicpublic: :. . ; 9.3.3 9.3.3 按照不同的方法派生类模板按照不同的方法派生类模板

46、 40 (2 2)类模板作基类,派生出新的类模板。但仅基类中用到类型参数)类模板作基类,派生出新的类模板。但仅基类中用到类型参数T T(而派(而派生的类模板中不使用生的类模板中不使用T T)。)。template class CB /CB template class CB /CB 为类模板(其中使用了类型参为类模板(其中使用了类型参数数T T),它将作为类模板),它将作为类模板 CA CA 的基类的基类T t; /T t; /私有数据为私有数据为T T 类型的类型的 public:public:T T gettgett() /() /用到类型参数用到类型参数T return t; T ret

47、urn t; . . ; ; template class template class CA:publicCA:public CB CB /CA /CA 为类模板,其基类为类模板,其基类CB CB 也为类模板。注意,类型参数也为类模板。注意,类型参数T T/将被将被“传递传递”给基类给基类CBCB,本派生类中并不使用该类型参数,本派生类中并不使用该类型参数T T double t1; /double t1; /私有数据成员私有数据成员 public:public:. ; /. ; /基类的名字应为实例化后的基类的名字应为实例化后的“CBCB”而并非仅使用而并非仅使用“CBCB”。例如,在本例

48、。例如,在本例的派生类说明中,要对基类进行指定时必须使用的派生类说明中,要对基类进行指定时必须使用“CBCB”而不可只使用而不可只使用“CBCB”: 41 (3 3)类模板作基类,派生出新的类模板,且基类与派生类中均使用同一个)类模板作基类,派生出新的类模板,且基类与派生类中均使用同一个类型参数类型参数T T。template class CB template class CB /CB /CB 为类模板(其中使用了类型参数为类模板(其中使用了类型参数T T),它将作为类模板),它将作为类模板CA CA 的基类的基类T t; /T t; /数据成员为数据成员为T T 类型的类型的 public

49、:public:T T gettgett() /() /用到类型参数用到类型参数T Treturn t;return t; . . ; ; template class template class CA:publicCA:public CB /CA CB /CA 为类模板,其为类模板,其基类基类CB CB 也为类模板。注意,类型参数也为类模板。注意,类型参数T T 将被将被“传递传递”给基类给基类CBCB;本派;本派生类中也将使用这同一个类型参数生类中也将使用这同一个类型参数T T T t1; /T t1; /数据为数据为T T 类型的类型的 public: .; public: .; 42

50、 (4 4)类模板作基类,派生出新的类模板,但基类中使用类型参数)类模板作基类,派生出新的类模板,但基类中使用类型参数T2T2,而派,而派生类中使用另一个类型参数生类中使用另一个类型参数T1T1(而不使用(而不使用T2T2)。)。template class CB template class CB /CB /CB 为类模板(其中使用了类型参数为类模板(其中使用了类型参数T2T2),它将作为类模板),它将作为类模板CA CA 的基类的基类T2 T2 t2t2; /; /数据为数据为T2 T2 类型的类型的 public: public: . . ; ; template class templ

51、ate class CA:publicCA:public CB /CA CB /CA 为类模板,其基类为类模板,其基类CB CB 也为类模板。注意,类型参数也为类模板。注意,类型参数T2 T2 将被将被“传递传递”给基类给基类CBCB;本派生类中还将使用另一个类型参数;本派生类中还将使用另一个类型参数T1 T1 T1 T1 t1t1; /; /数据为数据为T1 T1 类型的类型的 public: public: . . ; 9.3.3 9.3.3 按照不同的方法派生类模板按照不同的方法派生类模板 439 9.4 .4 程序实例程序实例- -设计一个链表类模板设计一个链表类模板 - - 参看书参

52、看书p318p318定义一个处理链表的类模板定义一个处理链表的类模板list,它含有它含有一个类型形参一个类型形参T,以指出每一链表项的以指出每一链表项的data数数据域的类型。据域的类型。#include#include44 templateclassliststructnodeTdata;node*next;*head,*tail;/*数据成员数据成员head与与tail均为指针均为指针。其中的。其中的head总指向链表的总指向链表的首项,而首项,而tail总指向链表的尾项。每当准备往链表中加入一个总指向链表的尾项。每当准备往链表中加入一个表项表项(及其表项及其表项data数据数据)时,程

53、序中首先使用时,程序中首先使用“newnode”来来动态生成一个新的表项空间,并动态生成一个新的表项空间,并“填入填入”该表项的该表项的data数据,数据,而后通过指针的改变与关联,将该表项加入到以而后通过指针的改变与关联,将该表项加入到以head为首以为首以tail为尾的当前链表结构中为尾的当前链表结构中(以形成一个更新后的链表以形成一个更新后的链表)。*/45public:list()/构造函数,创建一个构造函数,创建一个“空链表空链表”head=tail=NULL;voidInsert(T*item) /动态生成链表项空间,并将动态生成链表项空间,并将item所指向的所指向的T型数据放至

54、该项的型数据放至该项的data;/而后将新生成的该链表项插入到原链的链首(链表的而后将新生成的该链表项插入到原链的链首(链表的“栈栈”式用法)。式用法)。.;voidAppend(T*item)/动态生成链表项空间,并将动态生成链表项空间,并将item所指向的所指向的T型数据放入该项的型数据放入该项的data;/而后将新生成的该项附加到原链的链尾(链表的而后将新生成的该项附加到原链的链尾(链表的“队列队列”式用法)。式用法)。.;Tget()/取出链表首项的数据(取出链表首项的数据(data域值),并将该首项从链表中删去域值),并将该首项从链表中删去.;/类模板类模板list定义结束定义结束4

55、6 classpersonpublic:charname20;intage;floathight;/*注:若说明为注:若说明为“char*name;”,则主函数处要通过则主函数处要通过new为每一对象的为每一对象的name域申请动态空间!域申请动态空间!*/voidmain()personps;listlink1;listlink2;cout-Input5personsinformation-endl;for(inti=0;i 0 - 1 - 2 - 3 - 4head - 0 - 1 - 2 - 3 - 4 link2 link2链表链表: : head - 4head - 4号人员信息号人

56、员信息 - 3 - 3号人员信息号人员信息 - 2 - 2号人员信号人员信息息 - 1 - 1号人员信息号人员信息 - 0 - 0号人员信息号人员信息 */ */cout-Theresult-endl;for(i=0;i5;i+) ps=link2.get();/取出取出link2链表首项的人员信息链表首项的人员信息link2.Append(&ps);/将刚从将刚从link2首取来的人员信息,首取来的人员信息,/再一次附加到再一次附加到link2链表的链尾链表的链尾coutps.namelink1.get()endl;/输出输出link2链表人员信息的链表人员信息的name,/以及以及link

57、1链表表项中的对象的顺序号链表表项中的对象的顺序号48程序执行后的显示结果如下:程序执行后的显示结果如下: - - Input 5 persons information -Input 5 persons information -input 0 input 0 inf(name,age,hight):zhangLiinf(name,age,hight):zhangLi 20 1.68 20 1.68input 1 input 1 inf(name,age,hight):wangyueinf(name,age,hight):wangyue 21 1.72 21 1.72input 2 inpu

58、t 2 inf(name,age,hight):liminginf(name,age,hight):liming 19 1.75 19 1.75input 3 input 3 inf(name,age,hight):zhaoyiinf(name,age,hight):zhaoyi 19 1.78 19 1.78input 4 input 4 inf(name,age,hight):chenjininf(name,age,hight):chenjin 20 1.8 20 1.8 - The result - - The result -chenjinchenjin 0 0zhaoyizhaoyi 1 1liming 2liming 2wangyuewangyue 3 3zhangLizhangLi 4 449第第九九章章 结束结束 50

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 文学/艺术/历史 > 人文/社科

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号