收藏 分销(赏)

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

上传人:xrp****65 文档编号:13335883 上传时间:2026-03-03 格式:PPT 页数:77 大小:1.33MB 下载积分:10 金币
下载 相关 举报
C++面向对象程序设计教学PPT5.ppt_第1页
第1页 / 共77页
C++面向对象程序设计教学PPT5.ppt_第2页
第2页 / 共77页


点击查看更多>>
资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,第,5,章,多态性,多态性,是面向对象程序设计语言的又一重要特征,它是指不同对象接收到同一消息时会产生不同的行为。继承所处理的是,类与类之间的层次关系,问题,而多态则是处理类的层次结构之间,以及同一个类内部,同名函数,的关系问题。简单地说,多态就是在同一个类或继承体系结构的基类与派生类中,用同名函数来实现各种不同的功能。,5.1,静态,绑定和动态绑定,1,、多态,polymorphism,对象根据所接收的消息而做出动作,同样的消息为不同的对象接收时可导致完全不同的行动,该现象称为多态性。,简单的说:,单接口,多实现,2,、联编,一个程序常常会调用到来自于不同文件或,C+,库中的资源(如函数、对话框)等,需要经过编译、连接才能形成为可执行文件,在这个过程中要把调用函数名与对应函数(这些函数可能来源于不同的文件或库)关联在一起,这个过程就是,绑定,(,binding,),又称,联编。,5.1,静态,绑定和动态绑定,3,、静态绑定与静态绑定,静态绑定,又称静态联编,是指在编译程序时就根据调用函数提供的信息,把它所对应的具体函数确定下来,即在编译时就把调用函数名与具体函数绑定在一起。,动态绑定,又称动态联编,是指在编译程序时还不能确定函数调用所对应的具体函数,只有在程序运行过程中才能够确定函数调用所对应的具体函数,即在程序运行时才把调用函数名与具体函数绑定在一起。,4,、多态性的实现,编译时多态性:,-,静态联编,(,连接,)-,系统在编译时就决定如何实现某一动作,即对某一消息如何处理,.,静态联编具有执行速度快的优点,.,在,C+,中,的编译时多态性是通过,函数重载,和,运算符重载,实现的。,运行时多态性:,-,动态联编,(,连接,)-,系统在运行时动态实现某一动作,即对某一消息在运行过程实现其如何响应,.,动态联编为系统提供了灵活和高度问题抽象的优点,在,C+,中,的,运行,时多态性是通过,继承,和,虚函数,实现的。,5.1,静态绑定,和动态绑定,5.2,虚函数,5.2.1,虚函数的意义,1,、回顾:基类与派生类的,赋值相容,派生类对象可以赋值给基类对象。,派生类对象的地址可以赋值给指向基类对象的指针。,派生类对象可以作为基类对象的引用。,赋值相容的问题:,不论哪种赋值方式,都只能通过基类对象(或基类对象的指针或引用)访问到派生类对象从基类中继承到的成员,不能借此访问派生类定义的成员。,2,、虚函义使得通过基类对象的指针或引用访问派生类定义的成员可以施行。,5.2.1,虚,函数的意义,【,例,5-1】,某公司有经理、销售员、小时工等多类人员。经理按周计算薪金;销售员每月底薪,800,元,然后加销售提成,每销售,1,件产品提取销售利润的,5%,;小时工按小时计算薪金。每类人员都有姓名和身份证号等数据。为简化问题,把各类人员的共有信息抽象成基类,Employee,,其他人员则继承该类的功能。,/Eg5-1.cpp,#include,#include,using namespace std;,class Employee,public:,Employee(string,Name,string id)name=,Name,;Id=,id,;,string,getName,()return name;/,返回姓名,string,getID,()return Id;/,返回身份证号,float,getSalary,()return 0.0;/,返回薪水,void print()/,输出姓名和身份证号,cout,姓名,:name,tt,编号,:Id,endl,;,private:,string name;,string Id;,;,class,Manager:public,Employee,public:,Manager(string,Name,string,id,float,s=0.0):Employee(Name,id),WeeklySalary,=s;,void,setSalary(float,s),WeeklySalary,=s;/,设置经理的周薪,float,getSalary,()return,WeeklySalary,;/,获取经理的周薪,void print()/,打印经理姓名、身份证、周薪,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,虚,函数的意义,将基类,Employee,的,print,指定为虚函数,如下形式:,class Employee,virtual void print(),cout,姓名,:name,tt,编号,:Id,endl,;,;,将得到下面的程序运行结果:,经理:刘大海 编号,:NO0001,周工资,:128,经理:刘大海 编号,:NO0001,周工资,:128,经理:刘大海 编号,:NO0001,周工资,:128,基类指针或引用指向派生类对象时,虚函数与非虚函数的对象,图左为非虚函数,图右为虚函数,5.2.1,虚,函数的意义,1,、什么是虚函数,用,virtual,关键字修饰的成员函数,Virtual,关键字其实质是告知编译系统,被指定为,virtual,的函数采用动态联编的形式编译。,2,、虚函数的定义形式,class x,virtual f(,参数表,);,虚函数的虚特征:,基类指针指向派生类的对象时,通过该指针访问其虚函数时将调用派生类的版本;,例题没有虚函数的情况,class B,public:void f(),cout,B:f;,class D:public B,public:void f(),cout,f();,B:f,例题:虚函数版,class B,public:,virtual,void f(),cout,B:f;,class D:public B,public:void f(),cout,f();,总结:通过指向派生类对象的基类指针访问函数成员时,,非虚函数由指针类型决定调用的版本,虚函数由指针指向的实际对象决定调用的版本,D:f,5.2.2,虚,函数的特性,一旦将某个成员函数声明为虚函数后,它在继承体系中就永远为虚函数了,【,例,5-2】,虚函数与派生类的关系。,#include,#include,using namespace std;,class A,public:,void,f(int,i)cout,A,endl,;,;,class B:public A,public:,virtual void,f(int,i)cout,B,endl,;,;,class C:public B,public:,void,f(int,i)cout,C,endl,;,;,5.2.2,虚,函数的特性,class D:public C,public:,void f(,int)cout,Df(1);/,调用,A:f,pA,=,pA,-f(1);/,调用,A:f,pA,=,pA,-f(1);/,调用,A:f,pA,=,pA,-f(1);/,调用,A:f,5.2.2,虚,函数的特性,如果基类定义了虚函数,当通过基类指针或引用调用派生类对象时,将访问到它们实际所指对象中的虚函数版本。,例如,若把例,5-2,中的,main,的,pA,指针修改为,pB,,将会体现虚函数的特征。,void main(),A*,pA,a,;,B*,pB,b;C c;D d;,/,pB,=,pB,-f(1);/,错误,派生类不能访问基类对象,pB,=,pB,-f(1);/,调用,B:f,pB,=,pB,-f(1);/,调用,C:f,pB,=,pB,-f(1);/,调用,D:f,5.2.2,虚,函数的特性,只有通过基类对象的指针和引用访问派生类对象的虚函数时,才能体现虚函数的特性。,【,例,5-3】,只能通过基类对象的指针和引用才能实现虚函数的特性。,/Eg5-3.cpp,#include,using namespace std;,class B,public:,virtual void f(),cout,B:f,endl,;,;,class D:public B,public:,void f(),cout,D:f,f();,rB.f,();,本程序的运行结果如下:,第,1,行输出没有体现虚函数特征,B:f,D:f,D:f,5.2.2,虚,函数的特性,派生类中的虚函数要保持其虚特征,必须与基类虚函数的函数原型完全相同,否则就是普通的重载函数,与基类的虚函数无关。,【,例,5-4】,基类,B,和派生类,D,都具有成员函数,f,,但它们的参数类型不同,因此不能体现函数,f,在派生类,D,中的虚函数特性。,/Eg5-4.cpp,#include,using namespace std;,class B,public:,virtual void,f(int,i),cout,B:f,endl,;,;,5.2.2,虚,函数的特性,class D:public B,public:,int,f(char,c),cout,D:f,.cf(1);,rB.f(1);,本程序的运行结果如下:,B:f,B:f,5.2.2,虚,函数的特性,派生类通过从基类继承的成员函数调用虚函数时,将访问到派生类中的版本。,【,例,5-5】,派生类,D,的对象通过基类,B,的普通函数,f,调用派生类,D,中的虚函数,g,/Eg5-5.cpp,#include,using namespace std;,class B,public:,void f()g();,virtual void g(),cout,B:g,;,;,class D:public B,public:,void g(),cout,D:g,;,;,void main(),D d;,d.f,();,例题,5-6.cpp,class B,public:,void f(),cout,bf;,virtual void,vf,(),cout,bvf,;,void ff(),vf,();f();,virtual void,vff,(),vf,();f();,class D:public B,public:,void f(),cout,df,;,void ff()f();,vf,();,void,vf,(),cout,f();,pB,-ff();,pB,-,vf,();,pB,-,vff,();,bf,dvf,bf,dvf,dvf,bf,5.2.2,虚,函数的特性,只有类的非静态成员函数才能被定义为虚函数,类的构造函数和静态成员函数不能定义为虚函数。原因是虚函数在继承层次结构中才能够发生作用,而构造函数、静态成员是不能够被继承的。,内联函数也不能是虚函数。因为内联函数采用的是静态联编的方式,而虚函数是在程序运行时才与具体函数动态绑定的,采用的是动态联编的方式,即使虚函数在类体内被定义,,C+,编译器也将它视为非内联函数。,5.3,虚析,构函数,基类析构函数几乎总是为虚析构函数。假定使用,delete,和一个指向派生类的基类指针来销毁派生类对象,如果基类析构函数不为虚,就如一个普通成员函数,,delete,函数调用的就是基类析构函数。在通过基类对象的引用或指针调用派生类对象时,将致使对象析构不彻底!,【,例,5-7】,在非虚析构函数的情况下,通过基类指针对派生对象的析构是不彻底的。,#include,using namespace std;,class A,public:,A(),cout,call A:A(),endl,;,;,class,B:public,A,char*,buf,;,public:,B(int,i)buf,=new,chari,;,B(),delete,buf,;,cout,call B:(),endl,;,;,void main(),A*a=new B(10);,delete a;,程序运行结果:,call A:A(),此结果表明没有析构,buf,class A,public:,virtual A(),cout,call A:A(),endl,;,class,B:public,A,char*,buf,;,public:,B(int,i)buf,=new,chari,;,virtual B(),delete,buf,;,cout,call B:()f();,pb,-g();,5.5.1,、纯虚函数的概念,仅定义函数原型而不定义其实现的虚函数,Why pure function?,实用角度:占位手段,place-holder,方法学:接口定义手段,抽象表达手段,How?,class X,virtual,ret_type,func_name,(,param,),=0,;,5.5,纯虚函数,和抽象类,5.5.2,、抽象类的概念,What is an abstract class?,包含一个或多个纯虚函数的类,Using abstract class,不能实例化抽象类,但是可以定义抽象类的指针和引用,Converting abstract class to concrete class,定义一个抽象类的派生类,定义所有纯虚函数,5.5,纯虚,函数和抽象类,C+,对抽象类具有以下限定:,抽象类中含有纯虚函数,由于纯虚函数没有实现代码,所以不能建立抽象类的对象。,抽象类只能作为其他类的基类,可以通过抽象类对象的指针或引用访问到它的派生类对象,实现运行时的多态性。,如果派生类只是简单地继承了抽象类的纯虚函数,而没有重新定义基类的纯虚函数,则派生类也是一个抽象类。,5.5,纯虚,函数和抽象类,5.5,纯虚,函数和抽象类,抽象类的主要用途,作接口,5.5,纯虚,函数和抽象类,【,例,5-9】,抽象图形类及其应用。,/Eg5-9.cpp,#include,using namespace std;,class Figure,protected:,double,x,y,;,public:,void,set(double,i,double,j)x=i;y=j;,virtual void area()=0;/,纯虚函数,;,class,Triangle:public,Figure,public:,void,area()cout,三角形面积:,x*y*0.5,endl,;/,重写基类纯虚函数,;,class,Rectangle:public,Figure,public:,void,area(int,i)cout,这是矩形,它的面积是:,x*yarea();/L4,Figure&,rF,=t;,rF.set(20,20);,rF.area,();/L5,5.5.3,抽象,类的应用,【,例,5-10】,建立一个如右图所示图形类的继承层次结构。基类,Shape,是抽象类,通过它能够访问派生类,Point,、,Circle,、,Cylinder,的类名、面积、体积等内容。,虚函数及抽象类的应用,多态,从外部看:同一方法(函数)作用不同对象时,导致不同行为发生,从内部看:单接口、多实现,好处,代码重用,软件功能局部的修改和替代,抽象手段(抽象类),5.5.3,抽象类,的应用,5.5.3,抽象类,的应用,【,例,5-10】,建立一个如图,5-7,所示图形类的继承层次结构。基类,Shape,是抽象类,通过它能够访问派生类,Point,、,Circle,、,Cylinder,的类名、面积、体积等内容。,point,circle,cylinder,三种几何图形的成员,printName,(),print(),point,Point(),setPoint,(),getX,(),getY,(),X,y,area(),printName,(),print(),Circle,Circle(),setRadius,(),X,y,radius,area(),volume(),printName,(),print(),Cylinder,Cylinder(),setHeight,(),getVolume,X,y,radius,抽象出虚基类:,hape,point,Point(),setPoint,(),getX,(),getY,(),X,y,Circle,Circle(),setRadius,(),X,y,radius,area(),volume(),printShapeName,(),print(),Cylinder,Cylinder(),setHeight,(),getVolume,X,y,radius,shape,Shape,只是概念上的几何图形,永远不会有称为,shape,的对象存在,它的存在只是为了提供,point,,,circle,,,cylinder,的公有接口。所以,shape,的成员函数定义为:,area()return,0;,volume()return,0;,printShapeName,()=0;,Print()=0;,S,hape.h,#,ifndef,SHAPE_H,#define SHAPE_H,#include,class Shape,public:,virtual,double area()const return 0.0;,virtual,double volume()const return 0.0;,virtual,void,printShapeName,()const=0;,virtual,void print()const=0;,;,#,endif,Shape.cpp,不需要此源文件,因为没有函数要定义,Point.h,#,ifndef,POINT1_H,#define POINT1_H,#include,shape.h,class Point:public Shape,public:,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,P,oint.cpp,#include point1.h,Point:Point,(,int,a,int,b),setPoint,(a,b);,void,Point:setPoint,(,int,a,int,b),x=a;,y=b;,void,Point:print,()const,cout,x ,y ;,Circ,le.h,#,ifndef,CIRCLE1_H,#define CIRCLE1_H,#include point1.h,class Circle:public Point,public:,Circle(double r=0.0,int,x=0,int,y=0);,void,setRadius,(double);,double,getRadius,()const;,virtual double area()const;,virtual void,printShapeName,()const,cout,0?r:0;,double,Circle:getRadius,()const return radius;,double,Circle:area,()const,return 3.14159*radius*,radius,;,void,Circle:print,()const,Point:print,();,cout,;Radius=radius;,Cylin,der.h,#,ifndef,CYLINDR1_H,#define CYLINDR1_H,#include circle1.h,class Cylinder:public Circle,public:,Cylinder(double h=0.0,double r=0.0,int,x=0,int,y=0);,void,setHeight,(double);,double,getHeight,();,virtual,double area()const;,virtual,double volume()const;,virtual,void,printShapeName,()const,cout,0?h:0;,double,Cylinder:getHeight,()return height;,double,Cylinder:area,()const,return 2*,Circle:area,()+2*3.14159*,getRadius,()*height;,double,Cylinder:volume,()const,return,Circle:area,()*height;,void,Cylinder:print,()const,Circle:print,();,cout,;Height=height;,main.cpp,#include,#include,#include,shape.h,#include,point.h,#include,circle.h,#include,cylindr.h,void,virtualViaPointer,(const Shape*);,void,virtualViaReference,(const Shape,void,virtualViaPointer,(const Shape*,baseClassPtr,),baseClassPtr,-,printShapeName,();,baseClassPtr,-print();,cout,nArea,=area(),nVolume,=volume(),nn,;,void,virtualViaReference,(const Shape&,baseClassRef,),baseClassRef.printShapeName,();,baseClassRef.print,();,cout,nArea,=,baseClassRef.area,(),nVolume,=,baseClassRef.volume,(),nn,;,main.cpp,int,main(),cout,setiosflags,(,ios:fixed,|,ios:showpoint,),setprecision,(2);,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,;,ma,in.cpp,Shape*,arrayOfShapes,3;,arrayOfShapes,0 =,arrayOfShapes,1 =,arrayOfShapes,2 =,cout,Virtual function calls made off,base-class pointersn;,for(,int,i=0;i 3;i+),virtualViaPointer,(,arrayOfShapes,i );,cout,Virtual function calls made off,base-class referencesn;,for(,int,j=0;j,printShapeName,();,的过程,1,、将,&circle,传入,baseClassPtr,2,、访问,Cirlce,对象,3,、访问,circle,vtable,4,、访问,printShapeName,指针,在,tb,中,5,、执行,printShapeName,(对,circle),5.6,运行时,类型信息,1,、,RTTI,运行时类型信息(,Run-time Type Information,,,RTTI,)提供了在程序运行时刻确定对象类型的方法,是面向对象程序语言为解决多态问题而引入的一种语言特性,在最初的非多态程序程序设计语言中,并没有,RTTI,机制。,在,C+,中,用于支持,RTTI,的运算符有:,dynamic_cast,,,typeid,,,type_info,5.6.1,dyn,amic_cast,1,、,dynamic_cast,的用途,dynamic_cast,是一个强制类型转换操作符,主要用于多态基类的指针或引用与派生类指针或引用之间的转换,它是在程序运行时刻执行的。,const_cast,、,static_cast,和,reinterpret_cast,强制类型转换则是在编译时期完成的。,2,、,dynamic_cast,的用法,dynamic_cast,(,表达式,),5.6.1,dyn,amic_cast,3,、,dynamic_cast,强制类型,向上强制转换、向下强制转换,向上转换是指在类的继承层次结构中,从派生类向基类方向的转换,即把派生类对象的指针或引用转换成基类对象的指针或引用,这种转换常用,C+,的默认方式完成。,与向上强制转换的方向相反,向下转换是指在类的继承层次结构中,从基类向派生类方向的转换,即把基类对象的指针或引用转换成派生类对象的指针或引用。,【,例,5-11】,/Eg5-11.cpp,class Base,public:,virtual Base(),;,class,Derived:public,Base,void f(),cout,f in Derived!n,endl,;,;,void main(),Base*,pb,b,;,Derived d,*pd;,pb,=/,默认转换,编译时完成,是常用方式,pd=,pb,=,dynamic_cast,(/,向上转换,运行时完成,pb,=,dynamic_cast,(pd);/,向上转换,运行时完成,对例,5-11,,修改,main,见到向下转换,void main(),Base*,pb,b,;,Derived d,*pd;,pb,=,pd=,dynamic_cast,(,pb,);/L1,:向下强制转换,if(pd,),cout,ok;,else,cout,error!t;,pd=,dynamic_cast,(/L2,:向下强制转换,if(pd,),cout,ok;,else,cout,error!t;,pb,=,pd=,dynamic_cast,(,pb,);/L3,:向下强制转换,if(pd,),cout,ok!;,else,cout,error!,tn,;,5.6.1,dyn,amic_cast,在默认情况下,在类的继承体系结构中,当用基类对象的指针操作派生类对象时,只能通过该指针访问派生类中的虚函数(这些虚函数也是基类中的虚函数)。而那些在基类中没有被定义为虚函数,或派生类新增加的函数,通过基类指针是无法访问的。请看下面的例子。,【,例,5-12】,有,3,个类,B,、,D1,、,D2,,,B,是,D1,和,D2,的基类,通过,B,的指针能够访问派生类的虚函数,f,。,/Eg5-12.cpp,#include,#include,using namespace std;,class B,int,x;,public:,B(int,i)x,=i;,int,getx()return,x;,virtual void,f()cout,1:,基类,B,中的,f,x=x,endl,;,;,class D1:public B,int,x;,public:,D1(int,i):B(i,),virtual void f(),cout,2:,派生类,D1,中的,f,x=,getx,(),endl,;,;,class D2:public B,int,x;,public:,D2(int,i):B(i,),virtual void f(),cout,3:,派生类,D2,中的,f,x=,getx,(),endl,;,void g(),cout,f();,/,pb,-g();/B,中没有定义,g(),为虚函数,不能访问,void main(),B b(1);,D1 d1(2);,D2 d2(3);,AccessB(&b,);,AccessB(,AccessB(,修改,5-12,的,AccessB,,访问正确对象的成员函数!,利用,dynamic_cast,将例,5-10,中的,AccessB,函数改写为下面的形式,其余程序代码不作任何修改,就能够通过基类对象,B,的指针,pb,访问到派生类,D2,新增加的函数,g(),。,void,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=1,2:,派生类,D1,中的,f,x=2,4:,这是派生类,D2,特有的函数,其他类都没有!,-,5.6.1,dyn,amic_cast,在,VC+,中,dyn,amic_cast,的使用说明,Microsoft VC+,在默认环境下,,RTTI,机制是关闭的。,解决办法是打开,Microsoft VC+,的,RTTI,机制。方法是选择,VC+,的“工程,|,设置,”,(如果是英文版的,VC+,,则对应的菜单是“,project|setting,”,),系统弹出如图所示的对话框。,从“,Y,分类”的列表中选择“,C+Language”,,然后选择图中所示的“允许允许时间类型信息,RTTI”,前面的复选标识,见图中的圈释。,设置,VC+,的,RTTI,机制,5.6.1,dyn,amic_cast,dyn,amic_cast,应用,说明:,在用,dynamic_cast,进行基类与派生类的指针或引用之间的转换时,基类必须是多态的,即基类必须至少有一个虚函数。,只有在支持,RTTI,的程序环境中,才能使用,dynamic_cast,进行类型转换。,在向下强制类型转换时,只有当基类对象指针或引用实际指向了一个派生类对象时,,dynamic_cast,才能将它们转换成派生类对象的指针或引用,否则转换将不会成功。,5.6.2,typeid,typeid,操作符在程序运行时判定一个对象的真实数据类型,,typeid,定义于头文件,typeinfo,中,它的用法如下:,typeid(exp,),【,例,5-13】,用,typeid,判定数据的类型。,/Eg5-13.cpp,#include,using namespace std;,class A;,void main(),A a,*p;,A&,rA,=a;,cout,1:,typeid(a).name,(),endl,;,cout,2:,typeid(p).name,(),endl,;,cout,3:,typeid(rA).name,(),endl,;,cout,4:typeid(3).name(),endl,;,cout,5:,typeid(this,is,string).name,(),endl,;,cout,6:typeid(4+9.8).name(),endl,;,【,例,5-14】A,是,B,的基类,没有虚函数。当基类,A,的指针指向派生类,B,的对象时,,typeid,识别到的基类指针的类型仍然是基类,A,的类型,当,A,类作为类,B,对象的引用时也是这样。,/Eg5-14.cpp,#include,using namespace std;,class A,public:,void f(),;,class,B:public,A;,void main(),A a,*,pA,;,B b;,a=b;,pA,=,A&,rA,=b;,cout,1:,typeid(a).name,(),endl,;,cout,2:,typeid,(*,pA).name,(),endl,;,cout,3:,typeid(rA).name,(),endl,;,【,例,5-15】,在多态程序中,利用,typeid,获取基类指针所指的实际对象,并进行不同的成员函数调用。,/Eg5-15.cpp,#include,#include,using namespace std;,class B,int,x;,public:,virtual void f(),cout,1:,B:f,(),endl,;,;,class D1:public B,public:,virtual void g(),cout,2:D1:g(),endl,;,;,class D2:public B,int,x;,public:,virtual void f(),cout,3:D2:f(),endl,;,void h(),cout,f();,else if(,typeid,(*,pb,)=typeid(D1),D1*pd1=,dynamic_cast,(,pb,);,pd1-g();,else if(,typeid,(*,pb,)=typeid(D2),D2*pd2=,dynamic_cast,(,pb,);,pd2-h();,void main(),B b;,D1,d1,;,D2,d2,;,AccessB(&b,);/,输出:,1:,B:f,(),AccessB(/,输出,:2:D1:g(),AccessB(/,输出,:4:D2:h(),5.7,编程,实作,在本书,4.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,。下图是类的继承层次图。,5.7,编程,实作,为,comFinal,继承结构设计虚函数,show,5.7,编程,实作,编程过程如下:,(,1,)打开,4.9,节建立在目录,C:course,中的工程项目文件,com_main.dsw,。,(,2,)在类,comFinal,的成员函数,show,声明前面加上限定词,virtual,。,class,comFinal,virtual,void show();,;,(,3,)改写主程序,编写访问本课程类继承结构的接口函数,display,和主函数,为此可改写原来的主文件,com_main.cpp,,内容如下。,/,com_main.cpp,#include,comFinl.h,#include,Chemistry.h,#include,Account.h,#include,voi
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 百科休闲 > 其他

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服