欢迎来到三一办公! | 帮助中心 三一办公31ppt.com(应用文档模板下载平台)
三一办公
全部分类
  • 办公文档>
  • PPT模板>
  • 建筑/施工/环境>
  • 毕业设计>
  • 工程图纸>
  • 教育教学>
  • 素材源码>
  • 生活休闲>
  • 临时分类>
  • ImageVerifierCode 换一换
    首页 三一办公 > 资源分类 > PPT文档下载  

    《面向对象程序设计》多态.ppt

    • 资源ID:6529533       资源大小:315.50KB        全文页数:45页
    • 资源格式: PPT        下载积分:15金币
    快捷下载 游客一键下载
    会员登录下载
    三方登录下载: 微信开放平台登录 QQ登录  
    下载资源需要15金币
    邮箱/手机:
    温馨提示:
    用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)
    支付方式: 支付宝    微信支付   
    验证码:   换一换

    加入VIP免费专享
     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    《面向对象程序设计》多态.ppt

    2023/11/9,北京科技大学计算机系,1,C+大学基础教程,第10章 多态性 北京科技大学 计算机系,2023/11/9,北京科技大学计算机系,-2-,第十一章 多态性,11.1 多态性的概念 11.2 继承中的静态联编 11.3 虚函数和运行时的多态 11.4 纯虚函数和抽象类,2023/11/9,北京科技大学计算机系,-3-,多态性的概念,多态性是面向对象程序设计的重要特征之一。多态性是指发出同样的消息被不同类型的对象接收时导致不同的行为。擦 地板 窗户 脸,采用不同的工具,不同的方式。在c+中可以用相同的函数名,不同的函数操作来实现,函数重载:函数名相同,但是函数的参数个数或者参数类型不同,或者const标识,2023/11/9,北京科技大学计算机系,-4-,面向对象程序设计中多态的表现,总的来说,不同对象对于相同的消息有不同的响应,就是面向对象程序设计中的多态性。具体在程序中,多态性有两种表现的方式:同一个对象调用名字相同、但是参数不同的函数,表现出不同的行为。重载多态 在同一个类中定义的重载函数的调用。不同的对象调用名字和参数都相同的函数,表现出不同的行为。-运行多态 在派生类中重复定义 同名覆盖:使用派生类的定义 作用域符的使用:使用基类的定义,2023/11/9,北京科技大学计算机系,-5-,继承和派生中的多态,class A public:void f();class C:public A public:void f();void f(int x);,如果声明:C c1;则 c1.f();c1.f(int x);c1.A:f(),2023/11/9,北京科技大学计算机系,-6-,面向对象程序设计中多态的表现,面向对象程序设计中多态性表现为以下几种形式:重载多态:通过调用相同名字的函数,表现出不同的行为。运行多态:通过基类的指针或引用,调用不同派生类的同名函数,表现出不同的行为。许多面向对象程序设计的书籍中所说的多态性,就是这种多态。模板多态,也称为参数多态:通过一个模板,得到不同的函数或不同的类。这些函数或者类具有不同的特性和不同的行为。,2023/11/9,北京科技大学计算机系,-7-,多态性的概念,例1int max(int a,int b)return ab?a:b;int max(int a,int b,int c)return(int t=(ab?a:b)c?t:c;float max(float a,float b)void main()int a,b,f;float c,d;max(a,b);max(c,d);,在编译的时候,确定调用的是哪个max,静态联编;,函数重载,2023/11/9,北京科技大学计算机系,-8-,继承和派生中的多态,class A public:void f();class C:public A public:void f();void f(int x);,如果声明:C c1;则 c1.f();c1.f(int x);c1.A:f(),静态联编;,2023/11/9,北京科技大学计算机系,-9-,派生类对象调用同名函数,对于派生类对象调用成员函数,可以有以下的结论:派生类对象可以直接调用本类中与基类成员函数同名的函数,不存在二义性;在编译时就能确定对象将调用哪个函数,属于静态联编,不属于运行时的多态。,2023/11/9,北京科技大学计算机系,-10-,赋值兼容原则,一个公有派生类的对象在使用上可以被当作基类的对象,反之则禁止。具体表现在:derived d;base b;派生类的对象可以被赋值给基类对象。b=d;派生类的对象可以初始化基类的引用。base,2023/11/9,北京科技大学计算机系,-11-,赋值兼容规则举例-多态是否具有动态性,#include class B0/基类B0声明 public:void display()coutB0:display()endl;/公有成员函数;,定义了基类,2023/11/9,北京科技大学计算机系,-12-,class B1:public B0 public:void display()coutdisplay();/对象指针-成员名,定义了类族,定义了基类的对象指针,2023/11/9,北京科技大学计算机系,-13-,void main()/主函数B0 b0;/声明B0类对象B1 b1;/声明B1类对象D1 d1;/声明D1类对象B0*p;/声明B0类指针p=,B0:display(),B0:display(),B0:display(),2023/11/9,北京科技大学计算机系,-14-,概念复习,根据赋值兼容规则,下列哪一个陈述是正确的?【】公有派生类的对象可以赋值给基类的对象。任何派生类的对象可以赋值给基类的对象。基类的对象可以赋值给派生类的对象。间接基类的对象可以赋值给直接基类的对象。,2023/11/9,北京科技大学计算机系,-15-,多态的实现:联编,联编(Binding绑定):确定具体的操作对象。程序自身彼此关联的过程,确定程序中的操作调用与执行该操作的代码间的关系。静态联编:编译的多态动态联编:运行时的多态,int a;main()int a;a=7;,2023/11/9,北京科技大学计算机系,-16-,静态联编与动态联编,静态联编(静态束定)联编工作出现在编译阶段,用对象名或者类名来限定要调用的函数。动画动态联编联编工作在程序运行时执行,在程序运行时才确定将要调用的函数。,例,例,2023/11/9,北京科技大学计算机系,-17-,#includeclass Point public:Point(double i,double j)x=i;y=j;double Area()return 0.0;private:double x,y;class Rectangle:public Point public:Rectangle(double i,double j,double k,double l);double Area()return w*h;private:double w,h;,静态联编例,2023/11/9,北京科技大学计算机系,-18-,Rectangle:Rectangle(double i,double j,double k,double l):Point(i,j)w=k;h=l;void fun(Point 运行结果:Area=0,X,inaceesible,Y,inaceesible,W,private,H,private,15.0,25.0,3.0,5.2,2023/11/9,北京科技大学计算机系,-19-,例11.1 定义Circle类和Rectangle类为Shape类的派生类,通过Circle类和Rectangle类的对象调用重载函数getArea()显示对象的面积。/例11.1:shape.h#ifndef SHAPE_H#define SHAPE_Hclass Shape public:double getArea()const;void print()const;/Shape类定义结束,基类Shape的定义,课下读懂!,2023/11/9,北京科技大学计算机系,-20-,#includeclass Point public:Point(double i,double j)x=i;y=j;virtual double Area()return 0.0;private:double x,y;class Rectangle:public Point public:Rectangle(double i,double j,double k,double l);virtual double Area()return w*h;private:double w,h;void fun(Point,动态联编例,虚函数,运行结果:Area=375,运行结果:Area=0,声明虚函数的目的就是通知编译器,碰到函数名时不要马上选择静态联编,也有可能时动态联编的。,2023/11/9,北京科技大学计算机系,21,虚函数和运行时的多态,2023/11/9,北京科技大学计算机系,-22-,虚函数,虚函数是动态联编的基础。是非静态的成员函数。在类的声明中,在函数原型之前写virtual。virtual 只用来说明类声明中的原型,不能用在函数实现时。具有继承性,基类中声明了虚函数,派生类中无论是否说明,同原型函数都自动为虚函数。本质:不是重载声明而是覆盖。调用方式:通过基类指针或引用,执行时会根据指针或引用指向的对象的类,决定调用哪个函数。,2023/11/9,北京科技大学计算机系,-23-,例,#include class B0/基类B0声明public:/外部接口virtual void display()coutB0:display()endl;/虚成员函数;,2023/11/9,北京科技大学计算机系,-24-,class B1:public B0/公有派生 public:void display()coutB1:display()endl;class D1:public B1/公有派生 public:void display()coutD1:display()endl;,2023/11/9,北京科技大学计算机系,-25-,void fun(B0*ptr)/普通函数 ptr-display();void main()/主函数B0 b0,*p;/声明基类对象和指针B1 b1;/声明派生类对象D1 d1;/声明派生类对象p=/调用派生类D1函数成员,B0:display(),B1:display(),D1:display(),2023/11/9,北京科技大学计算机系,-26-,void fun(B0 ptr)/普通函数 ptr.display();void main()/主函数B0 b0,*p;/声明基类对象和指针B1 b1;/声明派生类对象D1 d1;/声明派生类对象b0=b0;fun(b0);/调用基类B0函数成员b0=b1;fun(b0);/调用基类B0函数成员b0=d1;fun(b0);/调用基类B0函数成员,B0:display(),B0:display(),B0:display(),2023/11/9,北京科技大学计算机系,-27-,例11.3 将例11.2进行修改,使得程序具有运行时的多态的效果。/例11.3:shape1.h#ifndef SHAPE_H#define SHAPE_Hclass Shape public:virtual double getArea()const;void print()const;/Shape类定义结束,基类Shape的定义,例11.3 课下读懂!,2023/11/9,北京科技大学计算机系,-28-,10.3.1 虚函数,要实现运行时的多态,需要以下条件:必须通过指向基类对象的指针访问和基类成员函数同名的派生类成员函数;或者用派生类对象初始化的基类对象的引用访问和基类成员函数同名的派生类成员函数;派生类的继承方式必须是公有继承;基类中的同名成员函数必须定义为虚函数。,2023/11/9,北京科技大学计算机系,-29-,例10.4 虚函数的正确使用。分析以下程序,编译时哪个语句会出现错误?为什么?将有错误的语句屏蔽掉以后,程序运行结果如何?其中哪些调用是静态联编,哪些是动态联编?#include class BBpublic:virtual void vf1()coutBB:vf1被调用n;virtual void vf2()coutBB:vf2被调用n;void f()coutBB:f被调用n;class DD:public BBpublic:virtual void vf1()coutDD:vf1被调用n;void vf2(int i)coutiendl;void f()coutDD:fn被调用;,有虚函数的基类,派生类,void main()DD d;BB*bp=,2023/11/9,北京科技大学计算机系,-30-,void main()DD d;BB*bp=,将这个语句注释掉后,运行结果将显示:DD:vf1被调用BB:vf2被调用BB:f被调用,函数调用bp-vf2(10);是错误的。因为派生类的vf2函数和基类的vf2函数的参数不同,派生类的vf2就不是虚函数,而是重载。,其中bp-vf1()调用是动态联编。bp-vf2()是静态联编。bp-f()也是静态联编。,2023/11/9,北京科技大学计算机系,-31-,10.3.2 虚函数的使用,虚函数必须正确的定义和使用。否则,即使在函数原型前加了virtual的说明,也可能得不到运行时多态的特性。必须首先在基类中声明虚函数。在多级继承的情况下,也可以不在最高层的基类中声明虚函数。例如在第二层定义的虚函数,可以和第三层的虚函数形成动态联编。但是,一般都是在最高层的基类中首先声明虚函数。,2023/11/9,北京科技大学计算机系,-32-,11.3.2 虚函数的使用,基类和派生类的同名函数,必须函数名、返回值、参数表全部相同,才能作为虚函数来使用。否则,即使函数用virtual来说明,也不具有虚函数的行为。静态成员函数不可以声明为虚函数。构造函数也不可以声明为虚函数。析构函数可以声明为虚函数,即可以定义虚析构函数。,2023/11/9,北京科技大学计算机系,-33-,10.3.3 虚析构函数,如果用动态创建的派生类对象的地址初始化基类的指针,创建的过程不会有问题:仍然是先调用基类构造函数,再执行派生类构造函数。但是,在用delete运算符删除这个指针的时候,由于指针是指向基类的,通过静态联编,只会调用基类的析构函数,释放基类成员所占用的空间。而派生类成员所占用的空间将不会被释放。,2023/11/9,北京科技大学计算机系,-34-,#include using namespace std;class Shape public:Shape()coutShape类构造函数被调用n;Shape()coutShape类析构函数被调用n;/Shape类定义结束class Circle:public Shape/派生类Circle的定义public:Circle(int xx=0,int yy=0,double rr=0.0)x=xx;y=yy;radius=rr;coutCircle类构造函数被调用n;Circle()coutCircle类析构函数被调用n;private:int x,y;/圆心座标double radius;/圆半径;/派生类Circle定义结束void main()Shape*shape_ptr;shape_ptr=new(Circle)(3,4,5);delete shape_ptr;,例11.5 定义简单的Shape类和Circle类,观察基类指针的创建和释放时如何调用构造函数和析构函数。,基类Shape的定义,主函数,程序运行后在屏幕上显示:Shape类构造函数被调用Circle类构造函数被调用Shape类析构函数被调用,2023/11/9,北京科技大学计算机系,-35-,10.3.3 虚析构函数,为了解决派生类对象释放不彻底的问题,必须将基类的析构函数定义为虚析构函数。格式是在析构函数的名字前添加virtual关键字。函数原型如下:virtual Shape();此时,无论派生类析构函数是不是用virtual来说明,也都是虚析构函数。再用delete shape_ptr来释放基类指针时,就会通过动态联编调用派生类的析构函数。,2023/11/9,北京科技大学计算机系,-36-,11.3.3 虚析构函数,将例11.5程序中的Shape析构函数作以上修改后,运行的结果将是:Shape类构造函数被调用Circle类构造函数被调用Circle类析构函数被调用Shape类析构函数被调用,2023/11/9,北京科技大学计算机系,-37-,11.4 纯虚函数和抽象类,2023/11/9,北京科技大学计算机系,-38-,抽象类的一般形式,带有纯虚函数的类称为抽象类:class 类名 virtual 类型 函数名(参数表)=0;/纯虚函数.;,一个函数声明为纯虚后,纯虚函数的意思是:我是一个抽象类!不要把我实例化!纯虚函数用来规范派生类的行为,实际上就是所谓的“接口”。它告诉使用者,我的派生类都会有这个函数。,2023/11/9,北京科技大学计算机系,-39-,作用,抽象类为抽象和设计的目的而建立,将有关的数据和行为组织在一个继承层次结构中,保证派生类具有要求的行为。对于暂时无法实现的函数,可以声明为纯虚函数,留给派生类去实现。,2023/11/9,北京科技大学计算机系,-40-,注意,抽象类只能作为基类来使用。不能声明抽象类的对象。构造函数不能是虚函数,析构函数可以是虚函数。eg.class Apublic:virtual void fun1()=0;A obj;,2023/11/9,北京科技大学计算机系,-41-,例,1)了解纯虚函数的定义2)了解纯虚类只能作为基类,派生其他类而用class Apublic:A()fun();virtual void fun()cout“A:fun”endl;class B:public A public:B()fun();void fun()cout“B:fun”endl;B b;,1 构造函数中调用的虚函数不具有动态联编,必然是调用的本类中的函数。2 Virtual void fun()=0;,virtual void fun()=0;,2023/11/9,北京科技大学计算机系,-42-,class Apublic:void foo()bar();private:virtual void bar().;class B:public Aprivate:virtual void bar().;void bar1(A*a)a-foo();,bar函数中调用a对象的foo,foo中调用虚函数bar,调用的是哪个bar。,2023/11/9,北京科技大学计算机系,-43-,一个类的虚函数在它自己的构造函数和析构函数中被调用的时候,它们就变成普通函数了,不“虚”了。也就是说不能在构造函数和析构函数中让自己“多态”。例如:class Apublic:A()foo();/在这里,无论如何都是A:foo()被调用!A()foo();/同上virtual void foo();class B:public Apublic:virtual void foo();void bar()A*a=new B;delete a;,2023/11/9,北京科技大学计算机系,-44-,多态有什么用?在面向对象的编程中,首先会针对数据进行抽象(确定基类)和继承(确定派生类),构成类层次。类层次的使用者在使用它们的时候,如果仍然在需要基类的时候写针对基类的代码,在需要派生类的时候写针对派生类的代码,就等于类层次完全暴露在使用者面前。如果这个类层次有任何的改变(增加了新类),都需要使用者“知道”(针对新类写代码)。这样就增加了类层次与其使用者之间的耦合,有人把这种情况列为程序中的“bad smell”之一。,2023/11/9,北京科技大学计算机系,-45-,总结,多态性是面向对象程序设计最重要的特点之一。本章介绍了多态性中最重要的两个表现:运行多态和参数多态。参数多态就是模板的使用。运行多态的表现就是:一种形态的语句:通过基类指针访问基类和派生类的同名函数;多种条件的执行:用不同派生类对象的地址初始化这个基类指针;,

    注意事项

    本文(《面向对象程序设计》多态.ppt)为本站会员(牧羊曲112)主动上传,三一办公仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知三一办公(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    备案号:宁ICP备20000045号-2

    经营许可证:宁B2-20210002

    宁公网安备 64010402000987号

    三一办公
    收起
    展开