好文档就是一把金锄头!
欢迎来到金锄头文库![会员中心]
电子文档交易市场
安卓APP | ios版本
电子文档交易市场
安卓APP | ios版本

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

50页
  • 卖家[上传人]:re****.1
  • 文档编号:567969065
  • 上传时间:2024-07-22
  • 文档格式:PPT
  • 文档大小:946.51KB
  • / 50 举报 版权申诉 马上下载
  • 文本预览
  • 下载提示
  • 常见问题
    • 第第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 函数模板的概念及说明函数模板的概念及说明 -- -- 参看书参看书p299-301p299-301     通通常常设设计计的的算算法法((处处理理语语句句))是是可可以以处处理理多多种种数数据据类类型型的的,,但但目目前前处处理理相相同同的的问问题题,,仍要分别定义多个类似的函数。

      仍要分别定义多个类似的函数 2 int max (int a, int b) {if(a>b)            return a;else            return b;    }     double max (double a, double b) { if(a>b)            return a;else            return b;    }     char max (char a, char b) {     ...    }     ... 3 实际上,若实际上,若““提取提取””出一个可变化的类型参数出一个可变化的类型参数T T,,则可则可““综综合合””成为如下的同一个成为如下的同一个函数(模板),函数(模板),它实际上代表着一组函它实际上代表着一组函数:数: T T maxmax (T a, T b){ (T a, T b){ if(a>b)if(a>b) 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(a>b) if(a>b) return a; return a; else else return b; return b;} } 4 函数模板定义的一般格式为:函数模板定义的一般格式为:template < class 类型形参名类型形参名1,,... ,,class 类型形参名类型形参名n > 返回类型返回类型 函数模板名函数模板名 ( ( 形参表形参表 ) { ) { 函数体函数体 } } 注意注意: :   1)1) 应应在在““返返回回类类型型””或或““形形参参表表””或或““函函数数体体””中中使使用上述的用上述的““类型形参名类型形参名” ” 。

      2)2) 调调用用处处则则类类似似于于一一般般函函数数,,用用户户只只需需给给出出具具体体的的实实参 3)3) 模模板板函函数数调调用用时时,,不不进进行行实实参参到到形形参参类类型型的的自自动动转转换 5 9.1.2 9.1.2 函数模板的应用举例函数模板的应用举例 -- -- 参看书参看书p302p3021. 1. 函数模板例函数模板例1 1  定义一个函数模板定义一个函数模板maxmax,,而后对它进行不同的调用而后对它进行不同的调用  # #include >  template T max (T a, T b){ template T max (T a, T b){ if(a>b) if(a>b) return a; return a; else else return b; return b;} }6 void main() {void main() { intint i1=-11, i2=0; i1=-11, i2=0; double d1, d2; double d1, d2; coutcout<<<>d1>>d2;>>d1>>d2; coutcout<<<

      板重载的方法 注注意意,,参参数数表表中中允允许许出出现现与与类类型型形形参参TypeType无无关关的的其其它它类类型的参数,如型的参数,如““intint size” size”  #include template  Type sum (Type * array, int size ){//求求array数组前数组前size个元素之和个元素之和    Type total=0;    for (int i=0;i Type sum (Type * a1, Type * a2, int size ){//求求a1数组与数组与a2数组前数组前size个元素之和个元素之和    Type total=0;    for (int i=0;i

      方式) 队列数据放于作为类成员的动态数组队列数据放于作为类成员的动态数组queuequeue之中,在构造之中,在构造函数中,将通过函数中,将通过newnew来生成该动态数组,动态数组来生成该动态数组,动态数组queuequeue的大的大小由类的私有数据成员小由类的私有数据成员MaxsizeMaxsize之值来确定但注意,此示例之值来确定但注意,此示例并没有循环使用上述的动态数组并没有循环使用上述的动态数组queuequeue空间即是说,队列中空间即是说,队列中至多可以存放至多可以存放MaxsizeMaxsize个数据项,即使取走若干项后有了空闲个数据项,即使取走若干项后有了空闲空间后也不可重新进行使用若稍加改造,使存取数据时首空间后也不可重新进行使用若稍加改造,使存取数据时首先通过对下标进行模先通过对下标进行模MaxsizeMaxsize的运算,则可实现循环使用动态的运算,则可实现循环使用动态数组数组queuequeue空间的功能,我们把它留作一个练习空间的功能,我们把它留作一个练习 13 #include #include template  class Queue {int Maxsize;      //队列的大小队列的大小int front,rear;           //元素放在元素放在queue[front+1]到到queue[rear]之中之中keytype *queue;    //动态数组动态数组queue,,用来存放队列数据用来存放队列数据 public:Queue (int size) {      //构造函数,生成动态数组来存放队列数据构造函数,生成动态数组来存放队列数据      Maxsize=size;      queue=new keytype[Maxsize];      front=rear=-1;    //意味着队列为空意味着队列为空 }; 14     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); }; 15 //Delete在类体外定义,函数名前要加类限定符在类体外定义,函数名前要加类限定符“Queue::”template  keytype Queue::Delete(void){    if (IsEmpty()){        cout << "the queue is empty"< void Queue::Add(const keytype & item){    if (IsFull())        cout << "the queue is full"< 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; i<4; 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 17 9.2. 9.2.2 2 类模板说明类模板说明    利利用用类类模模板板((带带类类型型参参数数或或普普通通参参数数的类),一次就可定义出具有共性的一组类。

      的类),一次就可定义出具有共性的一组类 即即,,可可使使得得所所定定义义类类中中的的某某些些数数据据成成员员、、某某些些成成员员函函数数的的参参数数、、某某些些成成员员函函数数的的返回值都可以是任意类型的返回值都可以是任意类型的 18 类模板定义格式如下:类模板定义格式如下:   template template < < 类类型型形形参参或或普普通通形形参参1 1的的说说明明,,... ... ,,类类型型形形参参或或普普通通形形参参n n的的说说明明 > > class class 类类模模板板名名 { { 带带上上述述类类型型形形参参或或普普通通形形参参名名的的类类定定义义体体 } }   说说明明类类型型形形参参时时,,使使用用““class class 类类型型形形参参名名””的的方方式式,,说说明明普通形参普通形参时,使用时,使用““< <类型类型> > 普通形参名普通形参名””的方式     注意注意: :   1)1) 类类定定义义体体中中应应使使用用上上述述的的““类类型型形形参参名名””及及““普普通通形形参参名名””。

      2)2) 利利用用类类模模板板说说明明类类对对象象时时,,要要随随类类模模板板名名同同时时给给出出对对应应于于类类型型形形参参或或普普通通形形参参的的具具体体实实参参((从从而而实实例例化化为为一一个个具具体体的的类)说明格式为:类)说明格式为: 类模板名类模板名 < < 形参形参1 1的相应实参,的相应实参,... ... ,形参,形参n n的相应实参的相应实参 > > 注注意意::类类型型形形参参的的相相应应实实参参为为类类型型名名,,而而普普通通形形参参的的相相应应实参必须为一个实参必须为一个常量常量 19 3)3) 类模板的成员函数既可以在类体内进行说明(自动类模板的成员函数既可以在类体内进行说明(自动按内联函数处理),也可以在类体外进行说明按内联函数处理),也可以在类体外进行说明 在类体外说明(定义)时使用如下格式:在类体外说明(定义)时使用如下格式: template < template < 形参形参1 1的说明,的说明,... ... ,形参,形参n n的说明的说明 > > 返回类型返回类型 类模板名类模板名 < < 形参形参1 1的名字,的名字,... ... ,形参,形参n n的名字的名字 >:: >::函数名函数名( ( 形参表形参表 ) { ) { ... // ... //函数体函数体} };;   上述的上述的““形参形参1 1的名字的名字””来自于来自于““形参形参1 1的说明的说明””,由,由““甩甩掉掉””说明部分的说明部分的““类型类型””而得,是对类型形参或普通形参的而得,是对类型形参或普通形参的使用。

      而使用而 “ “类模板名类模板名 < < 形参形参1 1的名字,的名字,... ... ,形参,形参n n的名字的名字 >:: >::””所所起的作用正是在类体外定义成员函数时在函数名前所加的类起的作用正是在类体外定义成员函数时在函数名前所加的类限定符限定符! !20 例例 如如 ,, 对对 具具 有有 一一 个个 类类 型型 参参 数数 T T的的 类类 模模 板板TestClassTestClass,,在在类类体体外外定定义义其其成成员员函函数数getDatagetData时时的的大致样式如下:大致样式如下:   template template T T TestClassTestClass::::getDatagetData( ( 形参表形参表 ) { ) { ... // ... //函数体函数体 }; };   其其中中的的““TestClassTestClass::::””所所起起的的作作用用正正是是在在类体外定义成员函数时在函数名前所加的类限定符类体外定义成员函数时在函数名前所加的类限定符! ! 21 9.2.9.2.3 3使用类型参数和普通参数的类模板使用类型参数和普通参数的类模板1 1 仅使用类型参数的类模板仅使用类型参数的类模板#include template  class TestClass {    public:     T buffer[10];        //T类型的数据成员类型的数据成员buffer数组大小固定为数组大小固定为10 (灵活性差灵活性差!)         T getData(int j);       //获取获取T类型类型buffer(数组数组)的第的第j个分量个分量 }; template T TestClass::getData(int j) {    return *(buffer+j);   }; 22 void main() {TestClass ClassInstA;     //char取代取代T,,从而实例化为一个具体的类从而实例化为一个具体的类 char cArr[6]="abcde"; for(int i=0; i<5; i++)ClassInstA.buffer[i]=cArr[i]; for(i=0; i<5; i++) {char res=ClassInstA.getData(i);cout< ClassInstF;      //实例化为另外一个具体的类实例化为另外一个具体的类double fArr[6]={12.1, 23.2, 34.3, 45.4, 56.5, 67.6}; for(i=0; i<6; i++)ClassInstF.buffer[i]=fArr[i]-10; for(i=0; i<6; i++) {double res=ClassInstF.getData(i);cout<template  class TestClass {  public:     int buffer[i];         //使使buffer的大小可变化,但其类型则固定为的大小可变化,但其类型则固定为int(灵活性差灵活性差!)           int getData(int j);   }; template int TestClass::getData(int j) {    return *(buffer+j);  }; 25 void main() {TestClass<6> ClassInstF;  double fArr[6]={12.1, 23.2, 34.3, 45.4, 56.5, 67.6}; for(i=0; i<6; i++)    ClassInstF.buffer[i]=fArr[i]-10; for(i=0; i<6; i++) {double res=ClassInstF.getData(i);cout<#include "string.h"template  class TestClass {  public:     T buffer[i];         //T类型的类型的buffer,,其大小随普通形参其大小随普通形参i的值变化的值变化(灵活性大灵活性大!)     T getData(int j);  }; template   T TestClass::getData(int j) {    return *(buffer+j);    }; 27 void main() {TestClass ClassInstA;char cArr[6]="abcde"; strcpy(ClassInstA.buffer, cArr); for(int i=0; i<5; i++) {    char res=ClassInstA.getData(i);    cout< ClassInstF;double fArr[6]={12.1, 23.2, 34.3, 45.4, 56.5, 67.6};for(i=0; i<6; i++)    ClassInstF.buffer[i]=fArr[i]-10;for(i=0; i<6; i++) {double res=ClassInstF.getData(i);cout<

      实际上,它们是类模板之实例化类的静态成类模板也允许有静态成员实际上,它们是类模板之实例化类的静态成员也就是说,对于一个类模板的每一个实例化类,其所有的对象共享员也就是说,对于一个类模板的每一个实例化类,其所有的对象共享其静态成员其静态成员例如:例如:templateclass C{templateclass C{ static T t static T t;; ////类模板的静态成员类模板的静态成员t t }; };类模板的静态成员在模板定义时是不会被创建的,其创建是在类的实例化之类模板的静态成员在模板定义时是不会被创建的,其创建是在类的实例化之后如: CA< CAaiobj1, aiobj2>aiobj1, aiobj2;; CAacobj1, acobj2CAacobj1, acobj2;; 对象对象 aiobj1 aiobj1 和和 aiobj2 aiobj2 将共享实例化类将共享实例化类 CA >的静态成员的静态成员 intint t t ,而,而对象对象acobj1acobj1,,acobj2 acobj2 将共享实例化类将共享实例化类CACA的静态成员的静态成员 char tchar t。

      9.3.1 9.3.1 静态成员及友元静态成员及友元31 2 2.类模板的友元.类模板的友元类模板定义中允许包含友元我们讨论类模板中的友元函数,因为说类模板定义中允许包含友元我们讨论类模板中的友元函数,因为说明一个友元类,实际上相当于说明该类的成员函数都是友元函数明一个友元类,实际上相当于说明该类的成员函数都是友元函数n① ① 该友元函数为一般函数,则它将是该类模板的所有实例化类的友该友元函数为一般函数,则它将是该类模板的所有实例化类的友元函数n② ② 该友元函数为一函数模板,但其类型参数与类模板的类型参数无该友元函数为一函数模板,但其类型参数与类模板的类型参数无关则该函数模板的所有实例化(函数)都是类模板的所有实例化类关则该函数模板的所有实例化(函数)都是类模板的所有实例化类的友元n③ ③ 更复杂的情形是,该友元函数为一函数模板,且它与类模板的类更复杂的情形是,该友元函数为一函数模板,且它与类模板的类型参数有关例如,函数模板可以用该类模板作为其函数参数的类型型参数有关例如,函数模板可以用该类模板作为其函数参数的类型在友元函数模板定义与相应类模板(的类型参数)有关时,该友元函在友元函数模板定义与相应类模板(的类型参数)有关时,该友元函数模板的实例有可能只是该类模板的某些特定实例化(而不是所有实数模板的实例有可能只是该类模板的某些特定实例化(而不是所有实例化)类的友元。

      例化)类的友元 9.3.1 9.3.1 静态成员及友元静态成员及友元32 大多数类模板不能任意进行实例化也就是说类模板的类型参数往往在实大多数类模板不能任意进行实例化也就是说类模板的类型参数往往在实例化时不允许用任意的类(类型)作为例化时不允许用任意的类(类型)作为““实参实参””模板的““实参实参””不不当,主要会在实例化后的函数成员调用中体现出来,例如当,主要会在实例化后的函数成员调用中体现出来,例如 template class stack { template class stack { ////栈中元素类型为栈中元素类型为T T 的的stack stack 类模类模板板T num [MAX]; T num [MAX]; //num //num 中存放栈的实际数据中存放栈的实际数据intint top; top; //top //top 为栈顶位置为栈顶位置 public: public: stack () { top=0; } //stack () { top=0; } //构造函数构造函数void push (T a) { void push (T a) { num[topnum[top++]=a; } ++]=a; } ////将数据将数据a“a“压入压入””栈顶栈顶void void showtopshowtop(){ (){ // // 显示栈顶数据显示栈顶数据////模板中通用的模板中通用的showtopshowtop,显示栈顶的那一个,显示栈顶的那一个T T 类型的数据类型的数据////(必须为(必须为可直接通过运算符可直接通过运算符““<<”<<”来显示的数据来显示的数据))if (top==0) if (top==0) coutcout << "stack is empty!"<< << "stack is empty!"<< endlendl; ; else else coutcout<<"<<"Top_MemberTop_Member:"<i1,i2; >i1,i2; stackc1,c2; stackc1,c2; stackf1,f2stackf1,f2; ; 等等。

      等等但如果采用用户定义类型而又未在该类中对运算符但如果采用用户定义类型而又未在该类中对运算符““<<”<<”进行重载时,就会产生问题,例如:进行重载时,就会产生问题,例如:stackcom1,com2;stackcom1,com2; 由于在执行由于在执行com1.showtop() com1.showtop() 函数时,将需要对函数时,将需要对complex complex 类类型的数据型的数据num[top-1] num[top-1] 通过使用运算符通过使用运算符““<<”<<”来进行输出,来进行输出,而系统和用户都没有定义过这种操作,因此,类模板而系统和用户都没有定义过这种操作,因此,类模板stack stack 的实例化的实例化stackstack就是不可行的了就是不可行的了 9.3.2 9.3.2 特例版本特例版本 34 如果用户在上述情况下,需要使如果用户在上述情况下,需要使stackstack可行,可可行,可有几个办法有几个办法n① ① 对于类对于类complex complex 追加插入运算符追加插入运算符“<<<<”的重载定义;的重载定义;n② ② 也可在类模板也可在类模板stack stack 的定义中增加一个的定义中增加一个“特例版本特例版本”(也称(也称“特殊版本特殊版本”)的定义。

      例如在上例中,可以在)的定义例如在上例中,可以在类模板定义之后给出如下形式的特例版本:类模板定义之后给出如下形式的特例版本: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 coutcout<<"<<"Top_MemberTop_Member:"<

      如此,当实,用于获取复数的实部和虚部如此,当实例化例化stackstack时将按该特例版本的定义进行时将按该特例版本的定义进行概括地说,当处理某一类模板中的可变类型概括地说,当处理某一类模板中的可变类型T T型数据时,如型数据时,如果处理算法并不能对所有的果处理算法并不能对所有的T T类型取值做统一的处理,此时类型取值做统一的处理,此时可通过使用专门补充的所谓特例版本来对具有特殊性的那可通过使用专门补充的所谓特例版本来对具有特殊性的那些些T T类型取值做特殊处理类型取值做特殊处理n③ ③ 也可以对函数模板,或类模板的个别函数成员补充其也可以对函数模板,或类模板的个别函数成员补充其““特例版本特例版本””定义例如,可将该例的例如,可将该例的showtopshowtop功能进一步划分,让功能进一步划分,让showtopshowtop调调用另一个新增加的用另一个新增加的showshow函数,而由函数,而由showshow函数具体考虑对两函数具体考虑对两种情况的处理:一种处理可直接通过运算符种情况的处理:一种处理可直接通过运算符““<<”<<”来显示来显示的数据,另一种的数据,另一种““特例版本特例版本””专用于处理专用于处理complexcomplex类型的数类型的数据。

      据 9.3.2 9.3.2 特例版本特例版本 36 实例实例class complex { class complex { ////复数类型复数类型complexcomplexdouble real, image;double real, image;public:public:......};};  template template class stack {class stack { T data [20]; T data [20]; intint top; top;public: public: void void showtop(voidshowtop(void); //); //显示栈顶数据显示栈顶数据 ... ...};}; 37 template  void stack::showtop(void)   //通用的通用的showtop//((T类型数据,可直接通过类型数据,可直接通过“<<”来一次性输出的数据)来一次性输出的数据){if (top==0)    cout << "stack is empty!"<< endl;else    cout<<"Top_Member:"<::showtop(void)   //专用专用于于complex类型的类型的showtop//显示栈顶的那一个显示栈顶的那一个complex型数据,它不可直接通过型数据,它不可直接通过“<<”一次性输出一次性输出!{if (top==0)     cout << "stack is empty!"<< endl;else    cout<<"Top_Member:"< 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} 39 通过继承可以产生派生类。

      通过继承同样可产生派生的类通过继承可以产生派生类通过继承同样可产生派生的类模板 n((1 1)一般类(其中不使用类型参数的类)作基类,派生出)一般类(其中不使用类型参数的类)作基类,派生出类模板(其中要使用类型参数)类模板(其中要使用类型参数)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 按照不同的方法派生类模板按照不同的方法派生类模板 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 return 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”。

      例如,在本例例如,在本例的派生类说明中,要对基类进行指定时必须使用的派生类说明中,要对基类进行指定时必须使用“CBCB”而不可只使用而不可只使用“CBCB”:: 41 ((3 3)类模板作基类,派生出新的类模板,且基类与派生类中均使用同一个)类模板作基类,派生出新的类模板,且基类与派生类中均使用同一个类型参数类型参数T Ttemplate class CB { template class CB { //CB //CB 为类模板(其中使用了类型参数为类模板(其中使用了类型参数T T),它将作为类模板),它将作为类模板CA CA 的基类的基类T t; //T t; //数据成员为数据成员为T T 类型的类型的 public: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 ((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 template 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 按照不同的方法派生类模板按照不同的方法派生类模板 43 9 9.4 .4 程序实例程序实例- -设计一个链表类模板设计一个链表类模板 -- -- 参看书参看书p318p318             定义一个处理链表的类模板定义一个处理链表的类模板list,,它含有它含有一个类型形参一个类型形参T,,以指出每一链表项的以指出每一链表项的data数数据域的类型据域的类型   #include  #include 44 template  class list {     struct node {  T data;   node * next;    } *head, *tail;          /*            数据成员数据成员head与与tail均为指针均为指针。

      其中的其中的head总指向链表的总指向链表的首项,而首项,而tail总指向链表的尾项每当准备往链表中加入一个总指向链表的尾项每当准备往链表中加入一个表项表项(及其表项及其表项data数据数据)时,程序中首先使用时,程序中首先使用“new node”来来动态生成一个新的表项空间,并动态生成一个新的表项空间,并“填入填入”该表项的该表项的data数据,数据,而后通过指针的改变与关联,将该表项加入到以而后通过指针的改变与关联,将该表项加入到以head为首以为首以tail为尾的当前链表结构中为尾的当前链表结构中(以形成一个更新后的链表以形成一个更新后的链表)       */ 45 public:    list() {    //构造函数,创建一个构造函数,创建一个“空链表空链表”head=tail=NULL;    };     void Insert (T * item) {      //动态生成链表项空间,并将动态生成链表项空间,并将item所指向的所指向的T型数据放至该项的型数据放至该项的data;;  //而后将新生成的该链表项插入到原链的链首(链表的而后将新生成的该链表项插入到原链的链首(链表的“栈栈”式用法)。

      式用法)  ...    };    void Append (T * item){   //动态生成链表项空间,并将动态生成链表项空间,并将item所指向的所指向的T型数据放入该项的型数据放入该项的data;;  //而后将新生成的该项附加到原链的链尾(链表的而后将新生成的该项附加到原链的链尾(链表的“队列队列”式用法)式用法)   ...    };     T get () {   //取出链表首项的数据(取出链表首项的数据(data域值),并将该首项从链表中删去域值),并将该首项从链表中删去   ...    };};    //类模板类模板list定义结束定义结束 46 class person{    public:       char name[20];      int age;     float hight;};/*  注:若说明为注:若说明为“char* name;”,,则主函数处要通过则主函数处要通过new为每一对象的为每一对象的name域申请动态空间!域申请动态空间!  */ void main() {    person ps;    list  link1;    list  link2;    cout<<"  --- Input 5 person's information ---"< 0 -> 1 -> 2 -> 3 -> 4head -> 0 -> 1 -> 2 -> 3 -> 4 link2 link2链表链表: : head -> 4head -> 4号人员信息号人员信息 -> 3 -> 3号人员信息号人员信息 -> 2 -> 2号人员信号人员信息息 -> 1 -> 1号人员信息号人员信息 -> 0 -> 0号人员信息号人员信息 */ */     cout<<"  ----- The result ----"<

      点击阅读更多内容
      手机版 | 川公网安备 51140202000112号 | 经营许可证(蜀ICP备13022795号)
      ©2008-2016 by Sichuan Goldhoe Inc. All Rights Reserved.