C面向对象程序设计教学PPT5

上传人:ni****g 文档编号:568644871 上传时间:2024-07-25 格式:PPT 页数:77 大小:1.33MB
返回 下载 相关 举报
C面向对象程序设计教学PPT5_第1页
第1页 / 共77页
C面向对象程序设计教学PPT5_第2页
第2页 / 共77页
C面向对象程序设计教学PPT5_第3页
第3页 / 共77页
C面向对象程序设计教学PPT5_第4页
第4页 / 共77页
C面向对象程序设计教学PPT5_第5页
第5页 / 共77页
点击查看更多>>
资源描述

《C面向对象程序设计教学PPT5》由会员分享,可在线阅读,更多相关《C面向对象程序设计教学PPT5(77页珍藏版)》请在金锄头文库上搜索。

1、第第5章章 多态性多态性多态性多态性是面向对象程序设计语言的又一是面向对象程序设计语言的又一重要特征,它是指不同对象接收到同一重要特征,它是指不同对象接收到同一消息时会产生不同的行为。继承所处理消息时会产生不同的行为。继承所处理的是的是类与类之间的层次关系类与类之间的层次关系问题,而多问题,而多态则是处理类的层次结构之间,以及同态则是处理类的层次结构之间,以及同一个类内部一个类内部同名函数同名函数的关系问题。简单的关系问题。简单地说,多态就是在同一个类或继承体系地说,多态就是在同一个类或继承体系结构的基类与派生类中,用同名函数来结构的基类与派生类中,用同名函数来实现各种不同的功能。实现各种不同

2、的功能。5.1静态绑定和动态绑定1、多态、多态polymorphism对象根据所接收的消息而做出动作,同样的消息为不同的对象接收时可导致完全不同的行动,该现象称为多态性。简单的说:单接口,多实现2、联编一个程序常常会调用到来自于不同文件或C+库中的资源(如函数、对话框)等,需要经过编译、连接才能形成为可执行文件,在这个过程中要把调用函数名与对应函数(这些函数可能来源于不同的文件或库)关联在一起,这个过程就是绑定绑定(binding),又称联编。联编。5.1静态绑定和动态绑定3、静态绑定与静态绑定、静态绑定与静态绑定静态绑定静态绑定又称静态联编,是指在编译程序时又称静态联编,是指在编译程序时就根

3、据调用函数提供的信息,把它所对应的就根据调用函数提供的信息,把它所对应的具体函数确定下来,即在编译时就把调用函具体函数确定下来,即在编译时就把调用函数名与具体函数绑定在一起。数名与具体函数绑定在一起。动态绑定动态绑定又称动态联编,是指在编译程序时还不能确定函数调用所对应的具体函数,只有在程序运行过程中才能够确定函数调用所对应的具体函数,即在程序运行时才把调用函数名与具体函数绑定在一起。4、多态性的实现编译时多态性:-静态联编(连接)-系统在编译时就决定如何实现某一动作,即对某一消息如何处理.静态联编具有执行速度快的优点.在C+中的编译时多态性是通过函数重载和运算符重载实现的。运行时多态性:-动

4、态联编(连接)-系统在运行时动态实现某一动作,即对某一消息在运行过程实现其如何响应.动态联编为系统提供了灵活和高度问题抽象的优点,在C+中的运行时多态性是通过继承和虚函数实现的。5.1静态绑定和动态绑定5.2 虚函数虚函数 5.2.1虚函数的意义1、回顾:基类与派生类的赋值相容派生类对象可以赋值给基类对象。派生类对象的地址可以赋值给指向基类对象的指针。派生类对象可以作为基类对象的引用。赋值相容的问题:不论哪种赋值方式,都只能通过基类对象(或基类对象的指针或引用)访问到派生类对象从基类中继承到的成员,不能借此访问派生类定义的成员。2、虚函义使得通过基类对象的指针或引用访问派生类定义的成员可以施行

5、。5.2.1 虚虚函数的意义函数的意义【例5-1】某公司有经理、销售员、小时工等多类人员。经理按周计算薪金;销售员每月底薪800元,然后加销售提成,每销售1件产品提取销售利润的5%;小时工按小时计算薪金。每类人员都有姓名和身份证号等数据。为简化问题,把各类人员的共有信息抽象成基类Employee,其他人员则继承该类的功能。/Eg5-1.cpp#include#includeusingnamespacestd;classEmployeepublic:Employee(stringName,stringid)name=Name;Id=id;stringgetName()returnname;/返回

6、姓名stringgetID()returnId;/返回身份证号floatgetSalary()return0.0;/返回薪水voidprint()/输出姓名和身份证号cout姓名:namett编号:Idendl;private:stringname;stringId;classManager:publicEmployeepublic:Manager(stringName,stringid,floats=0.0):Employee(Name,id)WeeklySalary=s;voidsetSalary(floats)WeeklySalary=s;/设置经理的周薪floatgetSalary()

7、returnWeeklySalary; /获取经理的周薪voidprint()/打印经理姓名、身份证、周薪cout经理:getName()tt编号:getID()tt周工资:getSalary()print();Employee&rM=m;rM.print();5.2.1 虚虚函数的意义函数的意义例5-1程序的运行结果如下:经理:刘大海编号:NO0001周工资:128姓名:刘大海编号:NO0001姓名:刘大海编号:NO0001输出的第输出的第2、3行表明,通过基类对象的指针和引用只访问到行表明,通过基类对象的指针和引用只访问到了在基类中定义的了在基类中定义的print函数。函数。5.2.1 虚

8、虚函数的意义函数的意义将基类Employee的print指定为虚函数,如下形式:classEmployeevirtualvoidprint()cout姓名:namett编号:Idendl;将得到下面的程序运行结果:经理:刘大海编号:NO0001周工资:128经理:刘大海编号:NO0001周工资:128经理:刘大海编号:NO0001周工资:128基类指针或引用指向派生类对象时,虚函数与非虚函数的对象,图左为非虚函数,图右为虚函数5.2.1 虚虚函数的意义函数的意义1、什么是虚函数用virtual关键字修饰的成员函数Virtual关键字其实质是告知编译系统,被指定为virtual的函数采用动态联编

9、的形式编译。2、虚函数的定义形式classxvirtualf(参数表);虚函数的虚特征:基类指针指向派生类的对象时,通过该指针访问其虚函数时将调用派生类的版本;例题没有虚函数的情况class Bpublic: void f ( ) cout B:f; ;class D : public Bpublic: void f ( ) cout f( );B:f例题:虚函数版classBpublic:virtualvoidf()coutB:f;classD:publicBpublic:voidf()coutf();总结:通过指向派生类对象的基类指针访问函数成员时,非虚函数由指针类型决定调用的版本虚函数由

10、指针指向的实际对象决定调用的版本D:f5.2.2虚函数的特性函数的特性 一旦将某个成员函数声明为虚函数后,它在继承体系中一旦将某个成员函数声明为虚函数后,它在继承体系中就永远为虚函数了就永远为虚函数了【例5-2】虚函数与派生类的关系。#include#includeusingnamespacestd;classApublic:voidf(inti)coutAendl;classB:publicApublic:virtualvoidf(inti)coutBendl;classC:publicBpublic:voidf(inti)coutCendl;5.2.2虚函数的特性函数的特性classD:p

11、ublicCpublic:voidf(int)coutDf(1);/调用A:fpA=&b;pA-f(1);/调用A:fpA=&c;pA-f(1);/调用A:fpA=&d;pA-f(1);/调用A:f5.2.2虚函数的特性函数的特性 如果基类定义了虚函数,当通过基类指如果基类定义了虚函数,当通过基类指针或引用调用派生类对象时,将访问到针或引用调用派生类对象时,将访问到它们实际所指对象中的虚函数版本。它们实际所指对象中的虚函数版本。例如,若把例5-2中的main的pA指针修改为pB,将会体现虚函数的特征。voidmain()A*pA,a;B*pB,b;Cc;Dd;/pB=&a;pB-f(1);/错

12、误,派生类不能访问基类对象pB=&b;pB-f(1);/调用B:fpB=&c;pB-f(1);/调用C:fpB=&d;pB-f(1);/调用D:f5.2.2虚函数的特性函数的特性只有通过基类对象的指针和引用访问派生类对象的虚函数时,才能体现虚函数的特性。【例5-3】只能通过基类对象的指针和引用才能实现虚函数的特性。/Eg5-3.cpp#includeusingnamespacestd;classBpublic:virtualvoidf()coutB:fendl;classD:publicBpublic:voidf()coutD:ff();rB.f();本程序的运行结果如下:第第1行输出没有体现

13、虚函数特征行输出没有体现虚函数特征B:fD:fD:f5.2.2虚函数的特性函数的特性 派生类中的虚函数要保持其虚特征,必须与基派生类中的虚函数要保持其虚特征,必须与基类虚函数的函数原型完全相同,否则就是普通类虚函数的函数原型完全相同,否则就是普通的重载函数,与基类的虚函数无关。的重载函数,与基类的虚函数无关。【例5-4】基类B和派生类D都具有成员函数f,但它们的参数类型不同,因此不能体现函数f在派生类D中的虚函数特性。/Eg5-4.cpp#includeusingnamespacestd;classBpublic:virtualvoidf(inti)coutB:fendl;5.2.2虚函数的特

14、性函数的特性classD:publicBpublic:intf(charc)coutD:f.cf(1);rB.f(1);本程序的运行结果如下:B:fB:f5.2.2虚函数的特性函数的特性 派生类通过从基类继承的成员函数调用虚函数时,将派生类通过从基类继承的成员函数调用虚函数时,将访问到派生类中的版本。访问到派生类中的版本。【例5-5】派生类D的对象通过基类B的普通函数f调用派生类D中的虚函数g/Eg5-5.cpp#includeusingnamespacestd;classBpublic:voidf()g();virtualvoidg()coutB:g;classD:publicBpublic

15、:voidg()coutD:g;voidmain()Dd;d.f();例题5-6.cppclassBpublic:voidf()coutbf;virtualvoidvf()coutbvf;voidff()vf();f();virtualvoidvff()vf();f();classD:publicBpublic:voidf()coutdf;voidff()f();vf();voidvf()coutf();pB-ff();pB-vf();pB-vff();bf dvf bf dvf dvf bf5.2.2虚函数的特性函数的特性只有类的非静态成员函数才能被定义为虚函数,类的构造函数和静态成员函数不

16、能定义为虚函数。原因是虚函数在继承层次结构中才能够发生作用,而构造函数、静态成员是不能够被继承的。内联函数也不能是虚函数。因为内联函数采用的是静态联编的方式,而虚函数是在程序运行时才与具体函数动态绑定的,采用的是动态联编的方式,即使虚函数在类体内被定义,C+编译器也将它视为非内联函数。5.3虚析构函数构函数基类析构函数几乎总是为虚析构函数。假定使用delete和一个指向派生类的基类指针来销毁派生类对象,如果基类析构函数不为虚,就如一个普通成员函数,delete函数调用的就是基类析构函数。在通过基类对象的引用或指针调用派生类对象时,将致使对象析构不彻底!【例5-7】在非虚析构函数的情况下,通过基

17、类指针对派生对象的析构是不彻底的。#include using namespace std;class Apublic: A() coutcall A:A()endl; ;class B:public A char *buf;public: B(int i)buf=new chari; B() delete buf; coutcall B:()endl;void main() A* a=new B(10); delete a;程序运行结果:call A:A()此结果表明没有析构bufclassApublic:virtualA()coutcallA:A()endl; ;classB:public

18、Achar*buf;public:B(inti)buf=newchari;virtualB()deletebuf;coutcallB:()f();pb-g();5.5.1、纯虚函数的概念、纯虚函数的概念仅定义函数原型而不定义其实现的虚函数仅定义函数原型而不定义其实现的虚函数Whypurefunction?实用角度:占位手段实用角度:占位手段place-holder方法学:接口定义手段,抽象表达手段方法学:接口定义手段,抽象表达手段How?class Xvirtual ret_type func_name (param) = 0;5.5纯虚函数纯虚函数和抽象类和抽象类5.5.2、抽象类的概念、抽

19、象类的概念Whatisanabstractclass?包含一个或多个纯虚函数的类包含一个或多个纯虚函数的类Usingabstractclass不能实例化抽象类不能实例化抽象类但是可以定义抽象类的指针和引用但是可以定义抽象类的指针和引用Convertingabstractclasstoconcreteclass定义一个抽象类的派生类定义一个抽象类的派生类定义所有纯虚函数定义所有纯虚函数5.5纯虚纯虚函数和抽象类函数和抽象类C+对抽象类具有以下限定:抽象类中含有纯虚函数,由于纯虚函数没有实现代码,所以不能建立抽象类的对象。抽象类只能作为其他类的基类,可以通过抽象类对象的指针或引用访问到它的派生类对

20、象,实现运行时的多态性。如果派生类只是简单地继承了抽象类的纯虚函数,而没有重新定义基类的纯虚函数,则派生类也是一个抽象类。5.5纯虚纯虚函数和抽象类函数和抽象类5.5纯虚纯虚函数和抽象类函数和抽象类抽象类的主要用途作接口作接口5.5纯虚纯虚函数和抽象类函数和抽象类【例5-9】抽象图形类及其应用。/Eg5-9.cpp#includeusingnamespacestd;classFigureprotected:doublex,y;public:voidset(doublei,doublej)x=i;y=j;virtualvoidarea()=0;/纯虚函数;classTriangle:public

21、Figurepublic:voidarea()cout三角形面积:x*y*0.5endl;/重写基类纯虚函数;classRectangle:publicFigurepublic:voidarea(inti)cout这是矩形,它的面积是:x*yarea();/L4Figure&rF=t;rF.set(20,20);rF.area();/L55.5.3 抽象抽象类的应用类的应用【例5-10】建立一个如右图所示图形类的继承层次结构。基类Shape是抽象类,通过它能够访问派生类Point、Circle、Cylinder的类名、面积、体积等内容。虚函数及抽象类的应用多态从外部看:同一方法(函数)作用不同

22、对象时,从外部看:同一方法(函数)作用不同对象时,导致不同行为发生导致不同行为发生从内部看:单接口、多实现从内部看:单接口、多实现好处代码重用代码重用软件功能局部的修改和替代软件功能局部的修改和替代抽象手段(抽象类)抽象手段(抽象类)5.5.3 抽象类抽象类的应用的应用5.5.3 抽象类抽象类的应用的应用【例例5-10】 建立一个如图建立一个如图5-7所示图形类的继承层所示图形类的继承层次结构。基类次结构。基类Shape是抽象类,通过它能够访问派是抽象类,通过它能够访问派生类生类Point、Circle、Cylinder的类名、面积、体积的类名、面积、体积等内容。等内容。pointcircle

23、cylinder三种几何图形的成员printName()print()pointPoint()setPoint()getX()getY() X,yarea()printName()print()CircleCircle()setRadius()X,y,radiusarea()volume()printName()print()CylinderCylinder()setHeight()getVolumeX,y,radius抽象出虚基类:hapepointPoint()setPoint()getX()getY() X,yCircleCircle()setRadius()X,y,radiusarea

24、()volume()printShapeName()print()CylinderCylinder()setHeight()getVolumeX,y,radiusshapeShape只是概念上的只是概念上的几何图形,永远不会几何图形,永远不会有称为有称为shape的对象的对象存在,它的存在只是存在,它的存在只是为了提供为了提供point,circle,cylinder的公的公有接口。所以有接口。所以shape的成员函数定义为:的成员函数定义为:area()return 0;volume()return 0;printShapeName()=0;Print()=0;Shape.h#ifndefS

25、HAPE_H#defineSHAPE_H#includeclassShapepublic:virtualdoublearea()constreturn0.0;virtualdoublevolume()constreturn0.0;virtualvoidprintShapeName()const=0;virtualvoidprint()const=0;#endifShape.cpp不需要此源文件,因为没有函数要定义Point.h#ifndef POINT1_H #define POINT1_H #include shape.h class Point : public Shape public:

26、 Point( int = 0, int = 0 ); void setPoint( int, int ); int getX() const return x; int getY() const return y; virtual void printShapeName() const cout Point: ; virtual void print() const; private: int x, y; ; #endif Point.cpp#includepoint1.hPoint:Point(inta,intb)setPoint(a,b);voidPoint:setPoint(inta,

27、intb)x=a;y=b;voidPoint:print()constcoutx,y;Circle.h#ifndefCIRCLE1_H#defineCIRCLE1_H#includepoint1.hclassCircle:publicPointpublic:Circle(doubler=0.0,intx=0,inty=0);void setRadius( double );doublegetRadius()const;virtual double area() const;virtualvoidprintShapeName()constcout 0 ? r : 0; double Circle

28、:getRadius() const return radius; double Circle:area() const return 3.14159 * radius * radius; void Circle:print() const Point:print(); cout ; Radius = radius; Cylinder.h#ifndefCYLINDR1_H#defineCYLINDR1_H#includecircle1.hclassCylinder:publicCirclepublic:Cylinder(doubleh=0.0,doubler=0.0,intx=0,inty=0

29、);voidsetHeight(double);doublegetHeight();virtualdoublearea()const;virtualdoublevolume()const;virtualvoidprintShapeName()constcout0?h:0;doubleCylinder:getHeight()returnheight;doubleCylinder:area()constreturn2*Circle:area()+2*3.14159*getRadius()*height;doubleCylinder:volume()constreturnCircle:area()*

30、height;voidCylinder:print()constCircle:print();cout;Height=height;main.cpp#include#include#includeshape.h#includepoint.h#includecircle.h#includecylindr.hvoidvirtualViaPointer(constShape*);voidvirtualViaReference(constShape&);voidvirtualViaPointer(constShape*baseClassPtr)baseClassPtr-printShapeName()

31、;baseClassPtr-print();coutnArea=area()nVolume=volume()nn;voidvirtualViaReference(constShape&baseClassRef)baseClassRef.printShapeName();baseClassRef.print();coutnArea=baseClassRef.area()nVolume=baseClassRef.volume()nn;main.cppint main() cout setiosflags( ios:fixed | ios:showpoint ) setprecision( 2 );

32、 Point point( 7, 11 ); Circle circle( 3.5, 22, 8 ); Cylinder cylinder( 10, 3.3, 10, 10 ); point.printShapeName(); point.print(); cout n; circle.printShapeName(); circle.print(); cout n; cylinder.printShapeName(); cylinder.print(); cout nn; main.cppShape*arrayOfShapes3;arrayOfShapes0=&point;arrayOfSh

33、apes1=&circle;arrayOfShapes2=&cylinder;coutVirtualfunctioncallsmadeoffbase-classpointersn;for(inti=0;i3;i+)virtualViaPointer(arrayOfShapesi);coutVirtualfunctioncallsmadeoffbase-classreferencesn;for(intj=0;jprintShapeName();的过程的过程1、将、将&circle传入传入baseClassPtr2、访问、访问Cirlce对象对象3、访问、访问circlevtable4、访问、访问

34、printShapeName指针,在指针,在tb中中5、执行、执行printShapeName(对(对circle)5.6 运行时运行时类型信息类型信息1、RTTI运行时类型信息(Run-timeTypeInformation,RTTI)提供了在程序运行时刻确定对象类型的方法,是面向对象程序语言为解决多态问题而引入的一种语言特性,在最初的非多态程序程序设计语言中,并没有RTTI机制。在C+中,用于支持RTTI的运算符有:dynamic_cast,typeid,type_info5.6.1 dynamic_cast1、dynamic_cast的用途dynamic_cast是一个强制类型转换操作符

35、,主要用于多态基类的指针或引用与派生类指针或引用之间的转换,它是在程序运行时刻执行的。const_cast、static_cast和reinterpret_cast强制类型转换则是在编译时期完成的。2、dynamic_cast的用法dynamic_cast(表达式表达式) 5.6.1 dynamic_cast3、dynamic_cast强制类型向上强制转换、向下强制转换向上转换是指在类的继承层次结构中,从派生类向基类方向的转换,即把派生类对象的指针或引用转换成基类对象的指针或引用,这种转换常用C+的默认方式完成。与向上强制转换的方向相反,向下转换是指在类的继承层次结构中,从基类向派生类方向的转

36、换,即把基类对象的指针或引用转换成派生类对象的指针或引用。【例5-11】/Eg5-11.cppclassBasepublic:virtualBase();classDerived:publicBasevoidf()coutfinDerived!nendl;voidmain()Base*pb,b;Derivedd,*pd;pb=&d;/默认转换,编译时完成,是常用方式pd=&d;pb=dynamic_cast(&d); /向上转换,运行时完成pb=dynamic_cast(pd); /向上转换,运行时完成对例5-11,修改main见到向下转换voidmain()Base*pb,b;Derived

37、d,*pd;pb=&b;pd=dynamic_cast(pb);/L1:向下强制转换if(pd)coutok;elsecouterror!t;pd=dynamic_cast(&b);/L2:向下强制转换if(pd)coutok;elsecouterror!t;pb=&d;pd=dynamic_cast(pb);/L3:向下强制转换if(pd)coutok!;elsecouterror!tn;5.6.1 dynamic_cast在默认情况下,在类的继承体系结构中,当用基类对象的指针操作派生类对象时,只能通过该指针访问派生类中的虚函数(这些虚函数也是基类中的虚函数)。而那些在基类中没有被定义为虚函

38、数,或派生类新增加的函数,通过基类指针是无法访问的。请看下面的例子。【例5-12】有3个类B、D1、D2,B是D1和D2的基类,通过B的指针能够访问派生类的虚函数f。/Eg5-12.cpp#include#includeusingnamespacestd;classBintx;public:B(inti)x=i;intgetx()returnx;virtualvoidf()cout1:基类B中的f,x=xendl;classD1:publicBintx;public:D1(inti):B(i)virtualvoidf()cout2:派生类D1中的f,x=getx()endl;classD2:p

39、ublicBintx;public:D2(inti):B(i)virtualvoidf()cout3:派生类D2中的f,x=getx()endl;voidg()coutf();/pb-g();/B中没有定义g()为虚函数,不能访问voidmain()Bb(1);D1d1(2);D2d2(3);AccessB(&b);AccessB(&d1);AccessB(&d2);修改5-12的AccessB,访问正确对象的成员函数!利用dynamic_cast将例5-10中的AccessB函数改写为下面的形式,其余程序代码不作任何修改,就能够通过基类对象B的指针pb访问到派生类D2新增加的函数g()。vo

40、id AccessB(B *pb) D2 *p=dynamic_cast(pb); if(p) /如果转换成功,就调用如果转换成功,就调用p-g() p-g(); else /如果转换不成功,调用如果转换不成功,调用p-f() pb-f();当将AccessB改写为上面的形式后,例5-10的运行结果如下。这就对了这就对了1:基类B中的f,x=12:派生类D1中的f,x=24:这是派生类D2特有的函数,其他类都没有!-5.6.1 dynamic_cast在VC+中dynamic_cast的使用说明的使用说明MicrosoftVC+在默认环境下,RTTI机制是关闭的。解决办法是打开Microsof

41、tVC+的RTTI机制。方法是选择VC+的“工程|设置”(如果是英文版的VC+,则对应的菜单是“project|setting”),系统弹出如图所示的对话框。从“Y分类”的列表中选择“C+Language”,然后选择图中所示的“允许允许时间类型信息RTTI”前面的复选标识,见图中的圈释。设置VC+的RTTI机制机制5.6.1 dynamic_castdynamic_cast应用应用说明:在用dynamic_cast进行基类与派生类的指针或引用之间的转换时,基类必须是多态的,即基类必须至少有一个虚函数。只有在支持RTTI的程序环境中,才能使用dynamic_cast进行类型转换。在向下强制类型转

42、换时,只有当基类对象指针或引用实际指向了一个派生类对象时,dynamic_cast才能将它们转换成派生类对象的指针或引用,否则转换将不会成功。5.6.2 typeid typeid操作符在程序运行时判定一个对象的真实数据类型,typeid定义于头文件typeinfo中,它的用法如下:typeid(exp)【例5-13】用typeid判定数据的类型。/Eg5-13.cpp#includeusingnamespacestd;classA;voidmain()Aa,*p;A&rA=a;cout1:typeid(a).name()endl;cout2:typeid(p).name()endl;cout

43、3:typeid(rA).name()endl;cout4:typeid(3).name()endl;cout5:typeid(thisisstring).name()endl;cout6:typeid(4+9.8).name()endl;【例5-14】A是B的基类,没有虚函数。当基类A的指针指向派生类B的对象时,typeid识别到的基类指针的类型仍然是基类A的类型,当A类作为类B对象的引用时也是这样。/Eg5-14.cpp#includeusingnamespacestd;classApublic:voidf();classB:publicA;voidmain()Aa,*pA;Bb;a=b;

44、pA=&b;A&rA=b;cout1:typeid(a).name()endl;cout2:typeid(*pA).name()endl;cout3:typeid(rA).name()endl;【例5-15】在多态程序中,利用typeid获取基类指针所指的实际对象,并进行不同的成员函数调用。/Eg5-15.cpp#include#includeusingnamespacestd;classBintx;public:virtualvoidf()cout1:B:f()endl;classD1:publicBpublic:virtualvoidg()cout2:D1:g()endl;classD2:

45、publicBintx;public:virtualvoidf()cout3:D2:f()endl;voidh()coutf();elseif(typeid(*pb)=typeid(D1)D1*pd1=dynamic_cast(pb);pd1-g();elseif(typeid(*pb)=typeid(D2)D2*pd2=dynamic_cast(pb);pd2-h();voidmain()Bb;D1d1;D2d2;AccessB(&b);/输出:1:B:f()AccessB(&d1);/输出:2:D1:g()AccessB(&d2);/输出:4:D2:h()5.7 编程编程实作实作在本书4.

46、9节设计的课程体系继承结构中,设计了comFinal、Account、Chemistry三个类,这些类的相关头文件comFinal.h、account.h、chemistry.h,以及类的实现文件comFinal.cpp、account.cpp、chemistry.cpp,都保存在目录C:course中。现对4.9节的编程实作进行完善,将comFinal、Account、Chemistry中的成员函数show设计成虚函数,并设计一个访问该类继承结构的接口函数display,此函数通过基类comFinal对象的指针,访问派生类Account、Chemistry类对象的虚函数show。下图是类的继

47、承层次图。5.7 编程编程实作实作为comFinal继承结构设计虚函数show5.7 编程编程实作实作编程过程如下:(1)打开4.9节建立在目录C:course中的工程项目文件com_main.dsw。(2)在类comFinal的成员函数show声明前面加上限定词virtual。classcomFinalvirtualvoidshow();(3)改写主程序编写访问本课程类继承结构的接口函数display和主函数,为此可改写原来的主文件com_main.cpp,内容如下。/com_main.cpp#includecomFinl.h#includeChemistry.h#includeAccount.h#includevoiddisplay(comFinal*p)p-show();voidmain()comFinala3;comFinalc(王十,78,78,76);Accounta1(张三星,98,78,97,67,87);Chemistryc1(光红顺,89,76,34,56,78);a0=c;a1=a1;a2=c1;for(inti=0;i3;i+)display(&ai);

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

最新文档


当前位置:首页 > 医学/心理学 > 基础医学

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