




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、 前一页 休息第十二章第十二章 多态性与虚函数多态性与虚函数C+语言程序设计计算机基础教学研究室计算机基础教学研究室 前一页 休息主要内容主要内容l12.1 多态性的概念多态性的概念l12.2 一个典型的例子一个典型的例子l12.3 虚函数虚函数l12.4 纯虚函数与抽象类纯虚函数与抽象类多态性多态性(polymorphism)是面向对象程序设计的一个是面向对象程序设计的一个重要特征。利用多态性可以设计和实现一个易于扩展重要特征。利用多态性可以设计和实现一个易于扩展的系统。的系统。多态的意思是一个事物有多种形态。在面向对象方法多态的意思是一个事物有多种形态。在面向对象方法中一般是这样表述多态性
2、的中一般是这样表述多态性的: 向不同的对象发送同一向不同的对象发送同一个消息,不同的对象在接收时会产生不同的行为个消息,不同的对象在接收时会产生不同的行为(即即方法方法)。也就是说,每个对象可以用自己的方式去响。也就是说,每个对象可以用自己的方式去响应共同的消息。应共同的消息。12.1 多态性的概念多态性的概念l 从系统实现的角度看,多态性分为两类从系统实现的角度看,多态性分为两类: 静态多态性和动静态多态性和动态多态性。态多态性。l以前学过的函数重载和运算符重载实现的多态性属于静态以前学过的函数重载和运算符重载实现的多态性属于静态多态性,在程序编译时系统就能决定调用的是哪个函数,多态性,在程
3、序编译时系统就能决定调用的是哪个函数,因此静态多态性又称编译时的多态性。因此静态多态性又称编译时的多态性。l 静态多态性是通过函数的重载实现的静态多态性是通过函数的重载实现的(运算符重载实质上运算符重载实质上也是函数重载也是函数重载)。l 动态多态性是在程序运行过程中才动态地确定操作所针动态多态性是在程序运行过程中才动态地确定操作所针对的对象。它又称运行时的多态性。对的对象。它又称运行时的多态性。l 动态多态性是通过虚函数动态多态性是通过虚函数(virtual function)实现的。实现的。在本章中主要介绍动态多态性和虚函数。在本章中主要介绍动态多态性和虚函数。通过继承而产生了相关的不同的
4、派生类,与基类成员同名通过继承而产生了相关的不同的派生类,与基类成员同名的成员在不同的派生类中有不同的含义。也可以说,多态的成员在不同的派生类中有不同的含义。也可以说,多态性是性是“一个接口,多种方法一个接口,多种方法”。 C+中的虚函数就是用来解决这个问题的。虚函数的中的虚函数就是用来解决这个问题的。虚函数的作用是允许在派生类中重新定义与基类同名的函数,并且作用是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函可以通过基类指针或引用来访问基类和派生类中的同名函数。数。例如,用同一个语句例如,用同一个语句“pt-display( );”可以调用不同
5、派生可以调用不同派生层次中的层次中的display函数,只需在调用前给指针变量函数,只需在调用前给指针变量pt赋以不赋以不同的值同的值(使之指向不同的类对象使之指向不同的类对象)即可。即可。12.3 虚函数虚函数 12.3.1 虚函数的作用虚函数的作用例例12.2 基类与派生类中有同名函数。基类与派生类中有同名函数。在下面的程序中在下面的程序中Student是基类,是基类,Graduate是派生类,它是派生类,它们都有们都有display这个同名的函数。这个同名的函数。#include #include using namespace std;/声明基类声明基类Studentclass Stu
6、dentpublic: Student(int, string,float);/声明构造函数声明构造函数 void display( ); /声明输出函数声明输出函数 protected: /受保护成员,派生类可以访问受保护成员,派生类可以访问 int num; string name; float score; ; 前一页 休息/Student类成员函数的实现类成员函数的实现Student:Student(int n, string nam,float s) /定义构造函数定义构造函数 num=n;name=nam;score=s;void Student:display( ) /定义输出函
7、数定义输出函数coutnum:numnname:namenscore:scorenn;/声明公用派生类声明公用派生类Graduateclass Graduate:public Studentpublic: Graduate(int, string, float, float); /声明构造函数声明构造函数 void display( ); /声明输出函数声明输出函数private: float pay;/ Graduate类成员函数的实现类成员函数的实现Graduate:Graduate(int n, string nam,float s,float p):Student(n,nam,s),p
8、ay(p) void Graduate:display( ) /定义输出函数定义输出函数 coutnum:numnname:namenscore:scorenpay=paydisplay( ); pt=&grad1; pt-display( ); return 0; 运行结果如下,请仔细分析。运行结果如下,请仔细分析。num:1001(stud1的数据的数据)name:Liscore:87.5num:2001 (grad1中基类部分的数据中基类部分的数据)name:wangscore:98.5下面对程序作一点修改,在下面对程序作一点修改,在Student类中声明类中声明display函数函数时
9、,在最左面加一个关键字时,在最左面加一个关键字virtual,即,即virtual void display( );这样就把这样就把Student类的类的display函数声明为虚函数。程序其函数声明为虚函数。程序其他部分都不改动。再编译和运行程序,请注意分析运行结他部分都不改动。再编译和运行程序,请注意分析运行结果果: num:1001(stud1的数据的数据)name:Liscore:87.5num:2001 (grad1中基类部分的数据中基类部分的数据)name:wangscore:98.5pay=563.5 (这一项以前是没有的这一项以前是没有的)C+规定,规定,当一个成员函数被声明为
10、虚函数后,其派生类中的同名函数当一个成员函数被声明为虚函数后,其派生类中的同名函数都自动成为虚函数。都自动成为虚函数。习惯上一般在每一层声明该函数时都加习惯上一般在每一层声明该函数时都加virtual,使,使程序更加清晰。程序更加清晰。由虚函数实现的动态多态性就是由虚函数实现的动态多态性就是: 同一类族中不同类的对象,同一类族中不同类的对象,对同一函数调用作出不同的响应。虚函数的使用方法是对同一函数调用作出不同的响应。虚函数的使用方法是: (1) 在基类用在基类用virtual声明成员函数为虚函数。这样就可以在声明成员函数为虚函数。这样就可以在派生类中重新定义此函数,为它赋予新的功能,并能方便
11、派生类中重新定义此函数,为它赋予新的功能,并能方便地被调用。地被调用。(2) 在派生类中重新定义此函数,要求函数名、函数类型、在派生类中重新定义此函数,要求函数名、函数类型、函数参数个数和类型全部与基类的虚函数相同,并根据派函数参数个数和类型全部与基类的虚函数相同,并根据派生类的需要重新定义函数体。生类的需要重新定义函数体。C+规定,规定,当一个成员函数被声明为虚函数后,其派生类当一个成员函数被声明为虚函数后,其派生类中的同名函数都自动成为虚函数。中的同名函数都自动成为虚函数。习惯上一般在每一层声习惯上一般在每一层声明该函数时都加明该函数时都加virtual,使程序更加清晰。,使程序更加清晰。
12、(3) 定义一个指向基类对象的指针变量,并使它指向同一类定义一个指向基类对象的指针变量,并使它指向同一类族中需要调用该函数的对象。族中需要调用该函数的对象。(4) 通过该指针变量调用此虚函数,此时调用的就是指针变通过该指针变量调用此虚函数,此时调用的就是指针变量指向的对象的同名函数。量指向的对象的同名函数。 前一页 休息#include iostream.hclass Animalpublic: void character() cout动物特征动物特征: :不同不同.n; virtual food() cout动物食物动物食物: :不同不同.n;class Giraffe:public An
13、imalpublic: void character() cout长颈鹿特征长颈鹿特征: :长颈长颈.n; virtual food() cout长颈鹿食物长颈鹿食物: :树叶树叶.n;class Elephant:public Animalpublic: void character()cout大象特征大象特征: :长鼻子长鼻子.n; virtual food() coutcharacter(); p-food();void main()Giraffe g; f(&g);/实参为派生类对象的地址实参为派生类对象的地址 Elephant e; f(&e);/实参为派生类对象的地址实参为派生类对
14、象的地址观察运行结果观察运行结果:12-(4)/12-(4)-1动物特征动物特征:不同不同.长颈鹿食物长颈鹿食物:树叶树叶.动物特征动物特征:不同不同.大象食物大象食物:草草.AnimalGiraffeElephant 前一页 休息void f(Animal &p)/形参为基类形参为基类对象的引用对象的引用p.character(); p.food();void main()Giraffe g; f(g);/实参为派生类对象实参为派生类对象 Elephant e; f(e);/实参为派生类对象实参为派生类对象void f(Animal p)/形参为基类形参为基类对象对象p.character(
15、); p.food();void main()Giraffe g; f(g);/实参为派生类对象实参为派生类对象 Elephant e; f(e);/实参为派生类对象实参为派生类对象若将程序的相应部分修改为如下两种形式,再观察运行结果若将程序的相应部分修改为如下两种形式,再观察运行结果运行结果:动物特征:不同.动物食物:不同.动物特征:不同.动物食物:不同.运行结果:动物特征:不同.长颈鹿食物:树叶.动物特征:不同.大象食物:草.有时在基类中将某一成员函数定为虚函数,并不是基类本有时在基类中将某一成员函数定为虚函数,并不是基类本身的要求,而是考虑到派生类的需要,在基类中预留了一身的要求,而是考
16、虑到派生类的需要,在基类中预留了一个函数名,具体功能留给派生类根据需要去定义。例如前个函数名,具体功能留给派生类根据需要去定义。例如前面程序中,基类面程序中,基类Point中没有求面积的中没有求面积的area函数,因为函数,因为“点点”是没有面积的,也就是说,基类本身不需要这个函是没有面积的,也就是说,基类本身不需要这个函数,所以在例数,所以在例12.1程序中的程序中的Point类中没有定义类中没有定义area函数。函数。但是,在其直接派生类但是,在其直接派生类Circle和间接派生类和间接派生类Cylinder中都中都需要有需要有area函数,而且这两个函数,而且这两个area函数的功能不同
17、,一个函数的功能不同,一个是求圆面积,一个是求圆柱体表面积。是求圆面积,一个是求圆柱体表面积。12.4 纯虚函数与抽象类纯虚函数与抽象类 12.4.1 纯虚函数纯虚函数l 在这种情况下应当将在这种情况下应当将area声明为虚函数。可以在基类声明为虚函数。可以在基类Point中加一个中加一个area函数,并声明为虚函数函数,并声明为虚函数: virtual float area( ) const return 0;其返回值为其返回值为0,表示,表示“点点”是没有面积的。其实,在基类中并是没有面积的。其实,在基类中并不使用这个函数,其返回值也是没有意义的。不使用这个函数,其返回值也是没有意义的。l
18、 为简化,可以不写出这种无意义的函数体,只给出函数的为简化,可以不写出这种无意义的函数体,只给出函数的原型,并在后面加上原型,并在后面加上“=0”,如,如virtual float area( ) const =0;/纯虚函数纯虚函数这就将这就将area声明为一个纯虚函数声明为一个纯虚函数(pure virtual function)。l 纯虚函数是在声明虚函数时被纯虚函数是在声明虚函数时被“初始化初始化”为为0的函数。的函数。纯虚函数纯虚函数 前一页 休息纯虚函数纯虚函数lclass 类名类名 virtual 类型 函数名(参数表)=0;/纯虚函数 l纯虚函数的重要作用是用来组织一个继承的层
19、次结构,纯虚函数的重要作用是用来组织一个继承的层次结构,并由它提供一个公共的根(即描述一组子类的共同的并由它提供一个公共的根(即描述一组子类的共同的操作接口),而完整的实现由子类完成。通过它多态操作接口),而完整的实现由子类完成。通过它多态地使用其中的成员函数。地使用其中的成员函数。l纯虚函数是一个在基类中声明的虚函数,在该基类中纯虚函数是一个在基类中声明的虚函数,在该基类中没有定义具体的操作内容没有定义具体的操作内容 ,要求个派生类根据实际需,要求个派生类根据实际需要定义自己的版本。要定义自己的版本。或或 对于暂时无法实现的函数,可对于暂时无法实现的函数,可以声明为纯虚函数,留给派生类去实现
20、。以声明为纯虚函数,留给派生类去实现。如果声明了一个类,一般可以用它定义对象。但是在面向如果声明了一个类,一般可以用它定义对象。但是在面向对象程序设计中,往往有一些类,它们不用来生成对象。对象程序设计中,往往有一些类,它们不用来生成对象。定义这些类的惟一目的是用它作为基类去建立派生类。它定义这些类的惟一目的是用它作为基类去建立派生类。它们作为一种基本类型提供给用户,用户在这个基础上根据们作为一种基本类型提供给用户,用户在这个基础上根据自己的需要定义出功能各异的派生类。用这些派生类去建自己的需要定义出功能各异的派生类。用这些派生类去建立对象。立对象。这种不用来定义对象而只作为一种基本类型用作继承
21、的类,这种不用来定义对象而只作为一种基本类型用作继承的类,称为抽象类称为抽象类(abstract class),由于它常用作基类,通常称,由于它常用作基类,通常称为抽象基类为抽象基类(abstract base class)。12.4.2 抽象类抽象类 前一页 休息#include #include class baseprotected: int x,y; public: virtual void setx(int i,int j=0) x=i; y=j; virtual void disp()=0; ;class square: public basepublic: void disp()
22、 coutx*xendl; ;class cube: public basepublic: void disp() coutx*x*xendl; ;class chpow: public basepublic: void disp() coutsetx(5); ptr-disp(); ptr=&C; ptr-setx(6); ptr-disp(); ptr=&D; ptr-setx(3,4); ptr-disp(); 运行结果:运行结果: 25 216 81 抽象类指针抽象类指针派生类派生类抽象类指针指向不同的派生抽象类指针指向不同的派生类对象类对象B、C、D,实现多态,实现多态性性bases
23、quarecubechpow 前一页 休息12.3 12.3 程序举例程序举例类名类名数据成员数据成员成员函数成员函数 vehicle名称含义名称功能wheels车轮个数vehicle初始化数据成员weight车重getwheels、getweight分别获得各数据成员值 print输出各数据成员值 truckwheelsweight基类vehicle类成员truck初始化数据成员的值(通过调用基类的构造函数初始化基类成员)payload载重量efficiency求卡车的载重效率 print输出数据成员的值(通过调用基类的print函数输出基类成员的值) 例例12-12-(5 5) 定义一个汽
24、车类定义一个汽车类vehiclevehicle,其数据成员有车轮个,其数据成员有车轮个数数wheelswheels和车重和车重weightweight;再定义一个派生类卡车类;再定义一个派生类卡车类trucktruck,包,包含新的数据成员载重量含新的数据成员载重量payloadpayload及成员函数载重效率。其中:及成员函数载重效率。其中:载重效率载重效率= =载重量载重量/ /(载重量(载重量+ +车重)车重) 前一页 休息#include iostream.hclass vehiclepublic:vehicle(int wl,float wt)wheels=wl; weight=wt
25、;int getwheels()return wheels;float getweight()return weight;void print()cout车轮:车轮:wheels个个endl; cout车重:车重:weight公斤公斤endl; private:int wheels;float weight;定义基类定义基类 前一页 休息class truck:public vehiclepublic:truck(int wl,float wt,float pl):vehicle(wl,wt)payload=pl;float efficiency()return(payload/(payloa
26、d+vehicle:getweight();void print()cout卡车:卡车:endl; vehicle:print(); cout载重:载重:payload公斤公斤endl; cout载重效率:载重效率:efficiency()endl; private:float payload;void main()truck T(8,4000,300000); T.print();不能直接代不能直接代之以之以weight运行结果:卡车:车轮:8个车重:4000公斤载重:300000公斤载重效率:0.986842调用基类成员函调用基类成员函数得到车重数得到车重派生类构造函数调派生类构造函数调用
27、基类构造函数用基类构造函数在本章例在本章例12.1介绍了以介绍了以Point为基类的点为基类的点圆圆圆柱体类的圆柱体类的层次结构。现在要对它进行改写,在程序中使用虚函数和层次结构。现在要对它进行改写,在程序中使用虚函数和抽象基类。类的层次结构的顶层是抽象基类抽象基类。类的层次结构的顶层是抽象基类Shape(形状形状)。Point(点点), Circle(圆圆), Cylinder(圆柱体圆柱体)都是都是Shape类的直类的直接派生类和间接派生类。接派生类和间接派生类。下面是一个完整的程序,程序如下下面是一个完整的程序,程序如下: 12.4.3 应用实例应用实例*第第(1)部分部分#includ
28、e 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类类class Point:public Shape /Point是是Shape的公用派的公用派生类生类public: Point(double=0,double=
29、0); void setPoint(double,double); double getX() const return x; double getY() const return y; virtual void shapeName() const coutPoint:endl; /对纯对纯虚函数进行定义虚函数进行定义protected: double x,y;Point:Point(double a,double b)x=a;y=b;void Point:setPoint(double a,double b)x=a;y=b; 前一页 休息/声明声明Circle类类class Circle:p
30、ublic Pointpublic: Circle(double x=0,double y=0,double r=0); void setRadius(double); double getRadius() const; virtual double area() const; virtual void shapeName() const coutCircle:endl; /对纯虚函数进行再定义对纯虚函数进行再定义protected: double radius;Circle:Circle(double a,double b,double r):Point(a,b),radius(r)void
31、 Circle:setRadius(double r)radius=r;double Circle:getRadius() const return radius;double Circle:area() constreturn 3.14159*radius*radius; 前一页 休息/声明声明Cylinder类类class Cylinder:public Circlepublic: Cylinder (double x=0,double y=0,double r=0,double h=0); void setHeight(double); double getHeight() const; virtual double area() const; v
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 家访关怀活动方案
- 宿舍学风活动方案
- 家长约谈活动方案
- 宝宝店活动策划方案
- 小儿牙科门诊活动方案
- 室内散步活动方案
- 家庭用品开业活动方案
- 审计系统三八节活动方案
- 小学灭蚊防病活动方案
- 寒假不宅家户外活动方案
- 餐厅控烟制度管理制度
- 《语文综合实践:走进传统节日 探寻文化根脉》(教学设计)-2024-2025学年中职语文高教版(2023)基础模块下册
- 男性生殖系统超声
- 黑龙江省2024年普通高校招生体育类本科批院校专业组投档分数线(历史类)
- 儿童学习习惯养成与学习能力提升
- 水闸地基施工方案
- 《建立合适边界:亲子教育课件》
- DB37-T 4516-2022 高速公路边坡光伏发电工程技术规范
- 课件:《教育强国建设规划纲要(2024-2035年)》学习宣讲
- 2023年遗传学考试题库(含答案)
- 课题申报参考:基于多模态大数据的大学生心理危机预警机制研究
评论
0/150
提交评论