




已阅读5页,还剩32页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第六章 多态性与虚函数61 多态性概述一、多态的分类二、多态的实现62一个典型的案例63 虚函数64 纯虚函数和抽象类一、纯虚函数二、抽象类三、 程序举例第六章 多态性与虚函数61 多态性概述所谓多态性是指:对于不同类的对象发出相同的消息将会有不同的实现。多态性也可以这样理解:在一般类中定义的属性或服务被特殊继承之后,可以具有不同的数据类型或不同的实现。多态性的目的在于:用同样的接口访问不同功能的函数。一、多态的分类从系统实现的角度划分静态多态性:在程序编译时,系统就能确定调用的是哪一个函数。如:函数重载和运算符重载等。动态多态性:在程序运行过程中,系统才能动态的确定调用的是哪一个对象。本章重点讲述的是:动态多态-虚函数。二、多态的实现编译时的多态性是通过静态联编实现的,而运行时的多态性是通过动态联编实现的。所谓联编是指把函数名与函数体的程序代码连接在一起的过程。1静态联编静态联编是指在程序编译连接阶段进行的联编,即编译器在程序开始运行前的编译阶段就确定程序所要进行的操作,从而调用固定的函数。2动态联编动态联编是指程序运行时进行的联编,即指编译器在连接期间不知道程序所要进行的操作,在运行时才确定调用哪个函数。62 一个典型的例子(P199)例6.1 建立一个Point(点)类,包含数据x,y(坐标点)。以它为基类,派生出一个Circle(圆)类,增加数据成员r(半径),再以Circle(圆)类为直接基类,派生出一个Cylinder(圆柱体)类,增加数据成员h(高)。要求编写程序,重载运算符“”,使之能用于输出以上类对象。(1)先声明基类Point(点)类#include class Point /声明类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(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;(2)声明派生类Circle(圆)类在上面的基础上,增加声明派生类Circle类的部分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 Circle &); 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() const return 3.14159*radius*radius; /重载运算符“”使之能按规定的形式输出圆的信息ostream &operator(ostream &output,const Circle &c)outputCenter=c.x,c.y, Radius=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; /pRef是Point类的引用变量,被c初始化 coutpRef:pRef;/输出pRef的信息,即点的信息 return 0; 注意:coutpRef:pRef;调用的是在Point中声明的运算符重载函数。即输出的是“点”的信息(3)声明Circle(圆)类的派生类Cylinder(圆柱体)在上面的基础上,再从Circle(圆)中派生出Cylinder(圆柱体)类,增加声明派生类Cylinder的部分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 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() const return height; /计算圆柱表面积float Cylinder:area() const return 2*Circle:area()+2*3.14159*radius*height;/计算圆柱体积float Cylinder:volume() const return 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=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;几点说明:1在圆柱体类(Cylinder)中定义的area()函数与圆类(Circle)中定义的area()函数同名,根据同名覆盖原则:cy1.area(); /调用的是Cylinder类中的area()函数2coutcy1; /调用的是Cylinder类中声明的重载运算符“函数3注意:3个运算符函数是重载的关系(形参的类型不同),而2个计算面积的area()函数不是重载的关系(形参的个数、类型均相同)其中:运算符重载函数即属于:静态多态性。63 虚函数(P204)在继承中,基类和派生类中定义了同名的成员函数,但希望编译器用基类的指针指向派生类的对象后,能够通过该指针来找到相应的派生类成员函数,则只能通过虚函数实现。一、虚函数的引入例62 虚函数的引例1#includeclass A public: void show() coutAendl; ;class B:public A public: void show() coutBshow(); pc=&b; pc-show(); return 0;例63 虚函数的引例2#includeclass basepublic: base(int x,int y) a=x; b=y; void show() coutbase-endl; couta bendl; private: int a,b;class derived:public basepublic: derived(int x,int y,int z ):base(x,y) c=z; void show() coutderived-endl; coutc=cshow(); pc=&mc; pc-show();通过例62与例63说明,由于C+的静态联编机制使得在程序开始运行前就已经将指向基类对象的指针PC与基类的成员函数show()连接在一起,因此,无论再将指针PC指向哪个对象,PC-show()调用的永远是基类中的成员函数show()。二、虚函数的作用和定义1虚函数的作用引入虚函数的目的:实现动态联编,即程序在运行时可根据指针pc所指的实际对象调用该对象所对应的成员函数。例64虚函数的作用#includeclass basepublic: base(int x,int y) a=x; b=y; virtual void show() /定义虚函数 coutbase-endl; couta bendl; private:int a,b;class derived:public basepublic: derived(int x,int y,int z ):base(x,y) c=z; void show() /重新定义虚函数 coutderived-endl; coutc=cshow(); pc=&mc; pc-show();2. 虚函数的定义虚函数定义的方法是:在定义类时在其成员函数的前面加上关键字virtual,其一般格式如下:virtual 函数类型 函数名(形参表)/函数体注意事项:(P207)l 只有类的成员函数才能定义为虚函数;l 派生类中与基类中的虚函数同名的函数,不论是否有虚函数说明,一律视为虚函数;l 在派生类中重新定义虚函数时,其函数原型,包括返回类型、函数名、参数个数、参数类型的顺序,都必须与基类中的原型相同。例65虚函数定义举例(*)#includeclass grandampublic: virtual void in_self() /定义虚函数 coutI am grandamendl; ;class mother:public grandampublic: virtual void in_self() /重新定义虚函数 coutI am motherendl; ;class daughter:public motherpublic: virtual void in_self() /重新定义虚函数 coutI am daughterin_self(); ptr=&m; ptr-in_self(); ptr=&d; ptr-in_self();三、虚函数与重载函数的关系(略 )虚函数可以看成是一种特殊的函数重载,但与普通函数重载在定义形式上和调用上不同。普通函数重载:其函数的参数或参数类型必须有所不同,函数的返回类型也可以不同;虚函数重载:要求其函数名、返回类型、参数个数、参数类型和顺序与基类中的虚函数原型完全相同。注意:虚函数重载必须在类层次中出现。例66 虚函数与重载函数的比较#includeclass basepublic: virtual void func1(); virtual void func2(); virtual void func3(); void func4();class derived:public basepublic: /重新定义func1()虚函数,virtual可省略 virtual void func1(); void func2(int x);/func2()作为普通函数重载,虚特性消失,原因是参数不同 char func3(); /error,原因是只有返回类型不同 void func4(); /普通函数重载;void base:func1() cout-base func1-n; void base:func2() cout-base func2-n; void base:func3() cout-base func3-n; void base:func4() cout-base func4-n; void derived:func1() cout-derived func1-n; void derived:func2(int x) cout-derived func2-n; void derived:func4() coutfunc1(); /调用:derived:func1() bp-func2(); /调用:base:func2() bp-func4(); /调用:base:func4()四、多继承与虚函数 (略)例67 多继承情况下的虚函数的调用#includeclass base1public: virtual void fun() /定义fun()是虚函数 cout-base1-n; ;class base2public: void fun() /定义fun()是普通的成员函数 cout-base2-n; ;class derived:public base1,public base2public: void fun() coutfun(); ptr2=&obj2; ptr2-fun(); ptr1=&obj3; ptr1-fun(); ptr2=&obj3; ptr2-fun();说明:多继承情况下的虚函数调用,可看成是多个单继承情况的组合,根据各自不同的继承路径,实现虚函数的应用。五、* 虚析构函数(P210)声明虚析构函数的方法:在析构函数前面加上virtual关键字。virtual 类名();如果一个基类的析构函数被说明为虚析构函数,则他的派生类中的析构函数也是虚析构函数,并且可以不在派生类析构函数前面加virtual关键字。虚析构函数的作用在于:当使用运算符delete删除一个对象时,能确保析构函数被正确执行。因为设置虚析构函数可以采用动态联编,于是可在运行时来选择析构函数。例68 #includeclass grandampublic: grandam() virtual grandam()coutthis is grandam:grandam().endl;class mother:public grandampublic: mother() mother()coutthis is mother:mother().endl;void main() grandam *f;f=new mother;delete f;六、虚函数举例(补充)例69 应用C+的多态性,计算三角形、矩形和圆的面积#includeclass figure /定义一个公共基类public: figure(double a,double b) x=a;y=b; /定义一个虚函数作为界面接口virtual void show_area() coutno area computation defined; coutfor this classn; protected:double x,y;/定义三角形派生类class triangle:public figure public: triangle(double a,double b):figure(a,b) ; void show_area() /虚函数重新定义,用做求三角形的面积cout三角形 with 高 ; cout and base y has an area of ; coutx*y*0.5endl; ;class square:public figure /定义矩形派生类public: square(double a,double b):figure(a,b) ; void show_area() /虚函数重新定义,用做求矩形的面积 cout矩形 with 尺寸 x; cout * y has an area of ; coutx*yendl; ;class circle:public figure /定义圆派生类public: circle(double a):figure(a,a) ; void show_area()/虚函数重新定义,用做求三角形的面积 cout圆 with 半径 x; cout has an area of ; coutx*x*3.1416show_area(); p=&s; p-show_area(); p=&c; p-show_area(); return 0;思考问题:什么情况下应当声明虚函数?64 纯虚函数和抽象类 (P211)一、纯虚函数纯虚函数是一种特殊的虚函数-没有具体实现的虚函数,其定义格式为:virtual 函数类型 函数名(参数表)=0;引入纯虚函数的目的:为某个基类的派生类提供一个公共界面,各派生类可根据其需要重新定义这些虚函数。例6。10 纯虚函数的使用#includeclass circlepublic: void setr(int x) r=x; virtual void show()=0; /纯虚函数protected: int r;class area :public circlepublic: void show() /重新定义虚函数coutarea is 3.14*r*rendl;class perimeter:public circlepublic: void show() /重新定义虚函数 coutperimeter is 2*3.14*rshow(); ptr=&ob2; ptr-show();二、抽象类抽象类是一种特殊的类,这种类不能定义对象,他的主要用途是用来组织一个继承的层次结构,并由它提一个公共的根,而相关的子类有它派生出来。创建人类这一概念,实际上它是一个不能有对象(实例)的类,这样的类的唯一用途在于被继承,这种类称为抽象类。抽象类以来描述一组子类的共同的操作接口,它只能用做基类,而完整的实现由子类完成。对抽象类来说,不可以定义具体对象,但可以定义一个指向它的指针,这样,就可以间接处理抽象类,或通过指针调用其派生类中的虚函数。三、 程序举例 (P213)例6.11 P213例6.4 虚函数和抽象类的应用使用虚函数和抽象类改写例6.2。类的层次结构的顶层是抽象基类Shape(形状)。Point(点),Circle(圆),Cylider(圆柱体)都是Shape类的直接派生类和间接派生类。 #include class Shape /声明抽象基类Shapepublic:virtual float area() const return 0.0; /虚函数virtual float volume() const return 0.0; /虚函数 virtual void shapeName()const=0;/纯虚函数;/声明Point类class Point:public Shape/Point是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 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; virtual 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() constreturn radius;float Circle:area() constreturn 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; virtual float volume() const;
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- IT外包合同常见风险及防范措施
- 建筑工程项目协调管理方案
- 小学生阅读兴趣培养策略分享
- 小学教学心理学试题辅导资料
- 建筑废弃物回收利用方案
- 跨境电商风险管理方案
- 八年级传统文化课程教学大纲
- 电动汽车运营管理规定
- 心脏病诊疗指南
- 旅行保险赔付预案
- 2.2中国的气候课件-八年级地理上学期湘教版
- DB11∕T 1130-2024 公共建筑节能运行管理与监测技术规程
- 2025电化学储能电站技术监督规程第5部分:化学与环保技术监督
- ppp审计管理制度
- 小儿鼾症麻醉管理要点
- 健康评估(第3版)课件6-2 泌尿系统常见症状评估
- 2025年高考湖南省物理真题(含解析)
- 律师合伙人管理制度
- DZ/T 0275.3-2015岩矿鉴定技术规范第3部分:矿石光片制样
- T/CASTEM 1007-2022技术经理人能力评价规范
- 中国银行校招笔试题目及答案
评论
0/150
提交评论