c++课件第十二章多态性与虚函数_第1页
c++课件第十二章多态性与虚函数_第2页
c++课件第十二章多态性与虚函数_第3页
c++课件第十二章多态性与虚函数_第4页
c++课件第十二章多态性与虚函数_第5页
已阅读5页,还剩25页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、第12章 多态性与虚函数12.1多态性的概念多态性分为两类:静态多态性和动态多态性。静态多态性是通过函数重载和运算符号重载实现的多态,在程序编译时就能决定调用的是哪一个函数,静态多态性也称为编译时的多态性。动态多态性是在程序运行过程中动态地确定操作所确定的对象,动态多态性是通过虚函数实现的。12.2一个典型的例子例12.1 先建立一个Point(点)类,包含数据成员x,y(坐标点)。以它为基类,派生出一个Circle(圆)类,增加数据成员r(半径),再以Circle类为直接基类,派生出一个Cylinder(圆柱体)类,在增加数据成员h(高)。要求编写程序,重载运算符“”,使之能用于输出以上类对

2、象。#include using namespace std;/声明类Pointclass Pointpublic:Point(float=0,float=0);void setPoint(float,float);float getX() const return x;float getY() const return y; friend ostream & operator(ostream &,const Point &);protected:float x,y;/定义Point类的成员函数/Point的构造函数Point:Point(float a,float b)x=a;y=b;/设置

3、x和y的坐标值void Point:setPoint(float a,float b)x=a;y=b;/输出点的坐标ostream & operator(ostream &output,const Point &p)outputp.x,p.yendl; return output;int main()Point p(3.5,6.4);coutx=p.getX(),y=p.getY()endl;p.setPoint(8.5,6.8);coutp(new):pendl;return 0;x=3.5,y=6.4p(new):8.5,6.8#include using namespace std;/声

4、明类Pointclass Pointpublic: Point(float=0,float=0); void setPoint(float,float); float getX() const return x; float getY() const return y; friend ostream & operator(ostream &,const Point &);protected: float x,y;/定义Point类的成员函数/Point的构造函数Point:Point(float a,float b)x=a;y=b;/设置x和y的坐标值void Point:setPoint(f

5、loat a,float b)x=a;y=b;/输出点的坐标ostream & operator(ostream &output,const Point &p)outputp.x,p.yendl; return output;class Circle:public Pointpublic: Circle(float x=0,float y=0,float r=0); void setRadius(float); float getRadius() const; float area () const; friend ostream &operator(ostream &,const Circl

6、e &); private: float radius;Circle:Circle(float a,float b,float r) :Point(a,b),radius(r)void Circle:setRadius(float r)radius=r;float Circle:getRadius() const return radius;float Circle:area() constreturn 3.14159*radius*radius;ostream &operator(ostream &output,const Circle &c)outputCenter=c.x,c.y, Ra

7、dius=c.radius, area=c.area()endl; return output;int main()Circle c(3.5,6.4,5.2); coutoriginal circle:nx=c.getX(), y=c.getY(), r=c.getRadius() , area=c.area()endl; c.setRadius(7.5); c.setPoint(5,5); coutnew circle:nc; Point &pRef=c; coutpRef:pRef; return 0;original circle:x=3.5, y=6.4, r=5.2, area=84

8、.9486new circle:Center=5,5, Radius=7.5, area=176.714pRef:5,5#include using namespace std;class Pointpublic: Point(float=0,float=0); void setPoint(float,float); float getX() const return x; float getY() const return y; friend ostream & operator(ostream &,const Point &);protected: float x,y;Point:Poin

9、t(float a,float b)x=a;y=b;void Point:setPoint(float a,float b)x=a;y=b;ostream & operator(ostream &output,const Point &p)outputp.x,p.yendl; return output;class Circle:public Pointpublic: Circle(float x=0,float y=0,float r=0); void setRadius(float); float getRadius() const; float area () const; friend

10、 ostream &operator(ostream &,const Circle &); protected: float radius;Circle:Circle(float a,float b,float r) :Point(a,b),radius(r)void Circle:setRadius(float r)radius=r;float Circle:getRadius() const return radius;float Circle:area() constreturn 3.14159*radius*radius;ostream &operator(ostream &outpu

11、t,const Circle &c)outputCenter=c.x,c.y,r= c.radius, area=c.area()endl; return output;class Cylinder:public Circlepublic: Cylinder(float x=0,float y=0,float r=0,float h=0); void setHeight(float); /设置圆柱高 float getHeight() const;/读取圆柱高 float area() const; /计算圆柱表面积 float volume() const;/计算圆柱体积 friend os

12、tream& operator(ostream&,const Cylinder&); protected: float height;Cylinder:Cylinder(float a,float b,float r,float h) :Circle(a,b,r),height(h)void Cylinder:setHeight(float h)height=h;float Cylinder:getHeight() const return height;float Cylinder:area() const return 2*Circle:area()+2*3.14159*radius*he

13、ight;float Cylinder:volume() constreturn Circle:area()*height;ostream &operator(ostream &output,const Cylinder& cy)outputCenter=cy.x,cy.y, r=cy.radius, h=cy.height narea=cy.area(), volume=cy.volume()endl; return output;int main()Cylinder cy1(3.5,6.4,5.2,10); coutnoriginal cylinder:nx=cy1.getX(), y=

14、cy1.getY(), r=cy1.getRadius(), h= cy1.getHeight()narea=cy1.area() , volume=cy1.volume()endl; cy1.setHeight(15); cy1.setRadius(7.5); cy1.setPoint(5,5); coutnnew cylinder:ncy1; Point &pRef=cy1; coutnpRef as a point:pRef; Circle &cRef=cy1; coutncRef as a Circle:cRef; return 0;original cylinder:x=3.5, y

15、=6.4, r=5.2, h=10area=496.623, volume=849.486new cylinder:Center=5,5, r=7.5, h=15area=1060.29, volume=2650.72pRef as a point:5,5cRef as a Circle:Center=5,5, r=7.5, area=176.71412.3虚函数12.3.1虚函数的作用例12.2 基类与派生类有同名函数#include #include using namespace std;class Studentpublic: Student(int,string,float); /v

16、irtual void display();void display();protected: int num; string name; float score;Student:Student(int n,string nam,float s)num=n;name=nam;score=s;void Student:display()coutnum:numnname:namenscore:scorenn;class Graduate:public Studentpublic: Graduate(int,string,float,float); void display();private: f

17、loat pay;void Graduate:display()coutnum:numnname:namenscore:scorenpay=paydisplay();pt=&grad1;pt-display();return 0;num:1001name:Liscore:87.5num:2001name:Wangscore:98.5如果void display();改为 virtual void display();则输出多一行:pay=563.5这种使用virtual修饰的成员函数称为虚函数。当在派生类中定义了一个同名的成员函数时,只要该成员函数的参数个数和相应类型以及它的返回类型与基类中同

18、名的虚函数完全一样,则无论是否为该成员函数使用virtual,它都将成为一个虚函数。使用虚函数保证了在通过一个基类类型的指针(包括引用)调用一个虚函数时,系统对该调用进行动态关联,即此时调用的是指针变量指向的对象的同名函数。但是,在通过一对象访问一虚函数时,则使用静态关联。12.3.2静态关联与动态关联 12.3.3在什么情况下应当声明虚函数12.3.4虚析构函数例12.3 基类中有非虚析构函数时的执行情况。#include using namespace std;class Pointpublic: Point()virtual Point()coutexecuting Point dest

19、ructorendl;class Circle:public Pointpublic:Circle()Circle() coutexecuting Circle destructorendl;private:int radus;int main()Point *p=new Circle;delete p;return 0;executing Point destructor如果将Point()coutexecuting Point destructorendl;改写为virtual Point()coutexecuting Point destructorendl;则输出结构为:executi

20、ng Circle destructorexecuting Point destructor显然这是我们想要的结果,因此,为了使用动态内存(new delete),应将基类的析构函数声明为虚析构函数。12.4纯虚函数与抽象类12.4.1纯虚函数virtual float area() const return 0;/空虚函数virtual float area() const =0;/纯虚函数纯虚函数没有函数体,也没有给它分配内存。它的定义留给派生类来做。12.4.2抽象类一个类可以说明多个纯虚函数,包含有纯虚函数的类称为抽象类。一个抽象类只能作为基类来派生新类,不能说明抽象类的对象。说明了纯

21、虚函数的派生类仍是抽象类。如果派生类中给出了基类所有纯虚函数的实现,则该派生类不再是抽象类。/使用纯虚函数的例子。#includeclass numberprotected: int val;public: number(int i)val = i; virtual void show() = 0;class hextype : public numberpublic: hextype(int i) : number(i) void show()couthexvaldecendl;class dectype : public numberpublic:dectype(int i) : numb

22、er(i)void show()coutdecvalshow();hextype h(15);nump=&h;nump-show();56f12.4.3应用实例例12.4 虚函数和抽象基类的应用。#include using namespace std;/声明抽象基类Shapeclass Shapepublic: virtual float area() const return 0.0;/虚函数 virtual float volume() const return 0.0;/虚函数 virtual void shapeName() const =0;/纯虚函数;/声明Point类 Poin

23、t是Shape的公用派生类class Point:public Shape public: Point(float=0,float=0); void setPoint(float,float); float getX() const return x; float getY() const return y; virtual void shapeName() const coutPoint:; /对纯虚函数进行定义 friend ostream & operator(ostream &,const Point &);protected: float x,y;Point:Point(float

24、a,float b)x=a;y=b;void Point:setPoint(float a,float b)x=a;y=b;ostream & operator(ostream &output,const Point &p)outputp.x,p.y; return output;/声明Circle类class Circle:public Pointpublic: Circle(float x=0,float y=0,float r=0); void setRadius(float); float getRadius() const; virtual float area() const; v

25、irtual void shapeName() const coutCircle:; /对纯虚函数进行再定义 friend ostream &operator(ostream &,const Circle &); protected: float radius;Circle:Circle(float a,float b,float r) :Point(a,b),radius(r)void Circle:setRadius(float r)radius=r;float Circle:getRadius() const return radius;float Circle:area() const

26、return 3.14159*radius*radius;ostream &operator(ostream &output,const Circle &c)outputc.x,c.y, r=c.radius; return output;/声明Cylinder类class Cylinder:public Circlepublic: Cylinder (float x=0,float y=0,float r=0,float h=0); void setHeight(float); float getHeight() const; virtual float area() const; virt

27、ual float volume() const; virtual void shapeName() const coutCylinder:; /对纯虚函数进行再定义 friend ostream& operator(ostream&,const Cylinder&); protected: float height;Cylinder:Cylinder(float a,float b,float r,float h) :Circle(a,b,r),height(h)void Cylinder:setHeight(float h)height=h;float Cylinder:getHeight

28、() const return height;float Cylinder:area() const return 2*Circle:area()+2*3.14159*radius*height;float Cylinder:volume() constreturn Circle:area()*height;ostream &operator(ostream &output,const Cylinder& cy)outputcy.x,cy.y, r=cy.radius , h=cy.height; return output;int main()Point point(3.2,4.5); /建

29、立Point类对象point Circle circle(2.4,12,5.6);/建立Circle类对象circle Cylinder cylinder(3.5,6.4,5.2,10.5);/建立Cylinder类对象cylinder point.shapeName();/静态关联 coutpointendl; circle.shapeName();/静态关联 coutcircleendl; cylinder.shapeName();/静态关联 coutcylinderendlshapeName(); /动态关联 coutx=point.getX(),y=point.getY()narea=

30、 area()nvolume=volume()shapeName(); /动态关联 coutx=circle.getX(),y=circle.getY()narea= area()nvolume=volume()shapeName();/动态关联 coutx=cylinder.getX(),y=cylinder.getY() narea=area()nvolume=volume()nn; return 0;Point:3.2,4.5Circle:2.4,12, r=5.6Cylinder:3.5,6.4, r=5.2, h=10.5Point:x=3.2,y=4.5area=0volume=0

31、Circle:x=2.4,y=12area=98.5203volume=0Cylinder:x=3.5,y=6.4area=512.959volume=891.96例编写一个用于计算各类形状的总面积的例子。这个程序用于计算各类形状的总面积。由于尚不能确定该程序处理的具体形状,我们先定义一个抽象的shape类。/shape.hclass shape public: virtual float area()=0;float total(shape *s,int n);有了shape类,就可以开始设计求面积程序:/shape.cpp#include shape.h#include float tot

32、al(shape * s ,int n)float sum = 0;for(int i=0;iarea();coutarea()endl;return sum;该程序可以用于求各类形状的面积之和。对于具体种类的形状,通过从shape派生一个类来对其进行描述,以重用上面的代码,并且不用重新对这些码进行编译。也就是说,可以把函数total()放在一个程序库中,以便其它程序在需要使用。例如:#include#includeshape.hclass triangle : public shapeprotected : float H , W;public:triangle(float h , floa

33、t w) H = h ; W = w ;float area() return H * W * 0.5 ; ;class rectangle :public triangle public :rectangle(float h, float w) :triangle(h,w) float area() return H * W ;class circle : public shape protected : float radius ;public : circle(float r ) radius = r; float area()return radius * radius * 3.14;

34、 ;void main()shape *s4 ;s0 = new triangle(3.0,4.0);s1 = new rectangle(2.0,4.0) ;s2 = new circle(5.0) ;s3 = new circle(8.0) ;float sum = total(s,4) ;cout sumendl;delete s0;delete s1;delete s2;delete s3;在该例中,shape类中的虚函数area仅起到为派生类提供一个一致的接口的作用,派生类中重定义的area() 用于决定以什么的方式计算面积。由于在shape类中不能对此作用决定,因此被说明为纯虚函数

35、。从此例子可以看出,赋值兼容规则使我们可将正方形、三角形、圆都视为形状,多态性又保证了函数total在对各种形状求面积之和时,无须关心当前正在计算哪种具体形状的面积。在需要时,函数total可从这些形状的对象那里获得该对象的面积,成员函数area保证了这点。特别声明:最好使用虚析构函数。#include class shape public: virtual float area()=0; virtual shape()coutdel shapen;float total(shape * s ,int n)float sum = 0;for(int i=0;iarea();coutarea()

36、endl;return sum;class triangle : public shapeprotected : float H , W;public:triangle(float h , float w) H = h ; W = w ;float area() return H * W * 0.5 ; triangle()coutdel trianglen;class rectangle :public triangle public :rectangle(float h, float w) :triangle(h,w) rectangle()coutdel rectanglen;float

37、 area() return H * W ;class circle : public shape protected : float radius ;public : circle(float r ) radius = r;circle()coutdel circlen; float area()return radius * radius * 3.14; ;void main()shape *s4 ;s0 = new triangle(3.0,4.0);s1 = new rectangle(2.0,4.0) ;s2 = new circle(5.0) ;s3 = new circle(8.

38、0) ;float sum = total(s,4) ;cout sumendl;delete s0;delete s1;delete s2;delete s3;6878.5200.96293.46del triangledel shapedel rectangledel triangledel shapedel circledel shapedel circledel shape实验:1:实验目的:(1)了解多态性的概念。(2)了解虚函数的作用及使用方法。(3)了解静态关联和动态关联的概念和用法。(4)了解纯虚函数和抽象类的概念和用法。2:实验内容: P416 1 43:实验结果。下面是虚析

39、构函数的真正用途例子,供有兴趣同学参考。数据库中保存各类对象的例子。/database.hclass object public:virtual int isEqual(object&)=0;virtual object();class database private:object* rec100;int pc,iterPc; public:database()pc=iterPc=0;int add(object&);object* read();void rewind()iterPc=0;int GetPc()return pc;int GetIterpc()return iterPc;d

40、atabase();database类的成员函数add()用于向数据库中增添一个对象,read() 对数据库进行顺序读,并返回读到的每一个对象,当所有对象被读完时,返回0。为使同一个对象在数据库中不保存两个备份,add()要将欲加入的对象与数据库中的对象进行相等比较,object类中的成员函数isEqual()用于比较对象,当两个对象相等时,它返回1。因为在没有明确具体种类的对象之前,无法给出isEqual()的定义,所以,它被说明为纯虚函数。/database.cpp#includedatabase.hint database : add(object& obj) for (int i=0;

41、iisEqual(obj)return 0;recpc+=&obj;return 1;object * database : read() if(iterPc pc) return reciterPc+; else return 0;database : database()for(int i=0;ipc;i+)delete reci;下面是使用这个程序的示例程序。/univ.h#include#include#include”database.h”class person : public objectprotected: char * name; person()name=0;public

42、:person(char *s)name=new charstrlen(s)+1;strcpy(name,s);virtual void print()=0;int isEqual(object& obj)person& man=(person&)obj;return strcmp(name, )=0;person()delete name;class student : virtual public person private: int val; public: student(char * s,int l):person(s)val=l; void print()cout

43、name valprint();univ.rewind();while(p=univ.read()!=0)p-print(); 读者分析一下该程序中虚析构函数的作用。如果不使用虚析构函数,在程序结束时,person类的成员name所指向的一段内存就不能释放。另外应注意,从databade类派生univDBase类目的是为替换database类的接口:使read返回一个person类类型的指针,这样,main函数就比较清晰可读。由于目前数据库中只保存person类的对象,所以,在函数read中进行强制类型转换是安全的。从这个程序可以看出,基类定义了比派生类更大的对象集合,因此,基于基类所做的抽象

44、所设计的程序必然可以用于派生类这种具体情形。将多个类中的共性抽象到基类中以便重用代码,这是面向对象和程序设计方法的一个重要思想,多态性从语言的实现上为代码重用提供了有力的支持。测试实例:#include#include/#includedatabase.hclass object public:virtual int isEqual(object&)=0;virtual object()coutobjectendl;class database private:object* rec100;int pc,iterPc; public:database()pc=iterPc=0;int add(

45、object&);object* read();void rewind()iterPc=0;int GetPc()return pc;int GetIterpc()return iterPc;database();int database : add(object& obj) for (int i=0;iisEqual(obj)return 0;recpc+=&obj;return 1;object * database : read()/coutdatabase read pc iterPcendl;if(iterPc pc)coutfff database read pc iterPcendl;return reciterPc+;else coutend database read pc iterPcendl; return 0;database : database()for(int i=0;ipc;i+)delete reci;class person : public objectprotected: char *

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论