欢迎来到淘文阁 - 分享文档赚钱的网站! | 帮助中心 好文档才是您的得力助手!
淘文阁 - 分享文档赚钱的网站
全部分类
  • 研究报告>
  • 管理文献>
  • 标准材料>
  • 技术资料>
  • 教育专区>
  • 应用文书>
  • 生活休闲>
  • 考试试题>
  • pptx模板>
  • 工商注册>
  • 期刊短文>
  • 图片设计>
  • ImageVerifierCode 换一换

    6 多态性与虚函数.ppt

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

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

    6 多态性与虚函数.ppt

    第第6 6章章 多态性与虚函数多态性与虚函数 6.1 6.1 多态性概述多态性概述 6.2 6.2 虚函数虚函数 6.3 6.3 纯虚函数和抽象类纯虚函数和抽象类在在OOPOOP中:中:窗口对象窗口对象 行为行为3 3 移动移动 同一消息同一消息 棋子对象棋子对象 行为行为4 46.1 6.1 多态性概述多态性概述多态性是面向对象程序设计的重要特征之一。多态性是面向对象程序设计的重要特征之一。多态性是面向对象程序设计的重要特征之一。多态性是面向对象程序设计的重要特征之一。多态性是指多态性是指多态性是指多态性是指发出同样的消息被不同类型的对象接收时导发出同样的消息被不同类型的对象接收时导发出同样的消息被不同类型的对象接收时导发出同样的消息被不同类型的对象接收时导致完全不同的行为。致完全不同的行为。致完全不同的行为。致完全不同的行为。多态的实现:多态的实现:多态的实现:多态的实现:1 1 函数重载函数重载函数重载函数重载2 2 运算符重载运算符重载运算符重载运算符重载3 3 虚函数虚函数虚函数虚函数4 4 类模板类模板类模板类模板 在C+中,多态的实现和联编这一概念有关。所谓联编就是把函数名与函数体的程序代码连接(联系)在一起的过程。静态联编静态联编 联编联编 动态联编动态联编 静态联编就是在编译阶段完成的联编。静态联编就是在编译阶段完成的联编。静态联编静态联编函数调用速度很快。效率高函数调用速度很快。效率高,但缺乏灵活性但缺乏灵活性;动态联编是运行阶段完成的联编。动态联编是运行阶段完成的联编。动态联编在运动态联编在运行时才能确定调用哪个函数行时才能确定调用哪个函数,它降低了程序的运行效率,它降低了程序的运行效率,但增强了程序的灵活性。但增强了程序的灵活性。C+C+实际上是采用了静态联编和动态联编相结合的实际上是采用了静态联编和动态联编相结合的联编方法。联编方法。编译时的多态性编译时的多态性 多态性多态性 运行时的多态性运行时的多态性 编译时的多态是通过编译时的多态是通过静态联编静态联编来实现的。来实现的。运行时的多态是通过运行时的多态是通过动态联编动态联编实现的。实现的。在在C+C+中中:编译时多态性主要是通过编译时多态性主要是通过函数重载函数重载和和运算符重载运算符重载实现的。实现的。运行时多态性主要是通过运行时多态性主要是通过虚函数虚函数来实现的。来实现的。6.2 6.2 虚虚 函函 数数 6.2.1 6.2.1 虚函数的引入虚函数的引入 6.2.2 6.2.2 虚函数的作用和定义虚函数的作用和定义 6.2.3 6.2.3 虚析构函数虚析构函数 6.2.4 6.2.4 虚函数与重载函数的关系虚函数与重载函数的关系 6.2.5 6.2.5 多继承与虚函数多继承与虚函数#includeclassbase/例例6.1-1虚函数引例虚函数引例 inta,b;public:base(intx,inty)a=x;b=y;voidshow()cout调用基类调用基类base的的show函数函数n;couta=a“b=bendl;classdirive:publicbaseintc;public:dirive(intx,inty,intz):base(x,y)c=z;voidshow()cout调用派生类调用派生类dirive的的show函数函数n;coutc=cshow();mp=&mc;mp-show();运行结果运行结果?6.2.1 虚函数的引入#include/例例6.1-1虚函数引例虚函数引例 classbaseinta,b;public:base(intx,inty)a=x;b=y;voidshow()cout调用基类调用基类base的的show函数函数n;couta=a“b=bendl;classdirive:publicbaseintc;public:dirive(intx,inty,intz):base(x,y)c=z;voidshow()cout调用派生类调用派生类dirive的的show函数函数n;coutc=cshow();mp=&mc;mp-show();程序运行结果不是:程序运行结果不是:调用调用基类基类basebase的的showshow函数函数a=50 b=50a=50 b=50调用调用派生类派生类dirivedirive的的showshow函数函数c=30c=30程序运行结果如下:程序运行结果如下:调用调用基类基类basebase的的showshow函数函数a=50 b=50a=50 b=50调用调用基类基类basebase的的showshow函数函数a=10 b=20a=10 b=20为为什什么么?在在C+C+中中规规定定:基基类类的的对对象象指指针针可可以以指指向向它它的的公公有有派生的对象派生的对象,但是当其指向公有派生类对象时但是当其指向公有派生类对象时,它只能访问派生类中从基类继承来的成员它只能访问派生类中从基类继承来的成员,而不能访问公有派生类中定义的成员而不能访问公有派生类中定义的成员,例如例如:classApublic:voidprint1().;classB:publicApublic:voidprint2().;voidmain()A*p1;/定义基类定义基类A的指针变量的指针变量p1Bop2;/定义派生类定义派生类B的对象的对象op2p1=&op2;/将指针变量将指针变量p1指向派生类指向派生类对象对象op2p1-print1();p1-print2();正正确确,基基类类指指针针变变量量p1p1可可以以访访问问派派生生类类中中从从基基类类继继承来承来的成员函数的成员函数print1()print1()错误错误,基基类指针变量类指针变量p1p1不能访问不能访问派生类中定派生类中定义义的成员函的成员函数数print2()print2()#include/例例6.1-1虚函数引例虚函数引例 classbaseinta,b;public:base(intx,inty)a=x;b=y;voidshow()cout调用基类调用基类base的的show函数函数n;couta=a“b=bendl;classdirive:publicbaseintc;public:dirive(intx,inty,intz):base(x,y)c=z;voidshow()cout调用派生类调用派生类dirive的的show函数函数n;coutc=cshow();mp=&mc;mp-show();指指向向基基类类的的指指针针变变量量,当当其其指指向向公公有有派派生生类类对对象象时时,可可以以直直接接访访问问派派生生类类中中从从基基类类继继承承来来的的成成员员,但但不不能能直直接接访访问问公公有有派派生类中定义的成员。生类中定义的成员。不不管管指指向向基基类类对对象象的的指指针针mpmp当当前前指指向向哪哪个个对对象象(基基类类对对象象或或派派生生类类对对象象),mp-show()mp-show()调调用用的的都都是基类中定义的是基类中定义的show()show()。例如:例如:void main()void main()base mb(50,50),*mp;base mb(50,50),*mp;dirivedirive mc(10,20,30);mc(10,20,30);mp=&mp=&mbmb;mp-show();mp-show();mp=&mc;mp-show();mp=&mc;mp-show();问题:能否用同一个语句问题:能否用同一个语句“mp-show()mp-show()”既能访既能访问基类又能访问派生类的同名函数呢?问基类又能访问派生类的同名函数呢?希望分别调用希望分别调用基基类类basebase的的show()show()函函数和数和派生类派生类dirivedirive的的 show()show()函数函数 C+C+中可以用中可以用虚函数虚函数来解决这个问题。来解决这个问题。6.2.2 6.2.2 虚函数的作用和定义虚函数的作用和定义 1 1虚函数的作用虚函数的作用 虚虚函函数数就就是是在在基基类类中中被被关关键键字字virtualvirtual说说明明,并并在在派生类中重新定义的函数。派生类中重新定义的函数。class baseclass base intint a,ba,b;public:public:.virtual virtual void show().void show().;class class dirive:publicdirive:public base base intint c;c;public:public:.void show().void show().;在基类中在基类中,show()show()定义为虚函数定义为虚函数在派生类中在派生类中,重新定义虚函数重新定义虚函数show()show()虚函数定义后,就可以通过基类指针访问基类和虚函数定义后,就可以通过基类指针访问基类和派生类中的虚函数。派生类中的虚函数。void main()void main()base mb(50,50),*mp;base mb(50,50),*mp;dirivedirive mc(10,20,30);mc(10,20,30);mp=&mp=&mbmb;mp-show();mp-show();mp=&mc;mp-show();mp=&mc;mp-show();调用基类调用基类basebase的的showshow()()函数函数 调用派生类调用派生类dirivedirive的的show()show()函数函数#include /例例5.2-1class base int a,b;public:base(int x,int y)a=x;b=y;virtual void show()cout调用基类调用基类base的的show函数函数n;couta=ab=bendl;class dirive:public base int c;public:dirive(int x,int y,int z):base(x,y)c=z;void show()cout 调用派生类调用派生类dirive的的show函数函数n;coutc=cshow();mp=&mc;mp-show();在基类中在基类中,show()show()定义为虚函数定义为虚函数在在派派生生类类中中,重重新新定义虚函数定义虚函数show()show()调用基类调用基类basebase的的show()show()函数函数调用派生类调用派生类dirivedirive的的show()show()函数函数#include /例例6.2-1class base int a,b;public:base(int x,int y)a=x;b=y;virtual void show()cout调用基类调用基类base的的show函数函数n;couta=ab=bendl;class dirive:public base int c;public:dirive(int x,int y,int z):base(x,y)c=z;void show()cout 调用派生类调用派生类dirive的的show函数函数n;coutc=cshow();mp=&mc;mp-show();程序运行结果如下:程序运行结果如下:调用基类调用基类basebase的的showshow函数函数a=50 b=50a=50 b=50调用派生调用派生类类dirivedirive的的showshow函数函数c=30c=30调用基类调用基类basebase的的show()show()函数函数调用派生类调用派生类dirivedirive的的show()show()函数函数 为什么把基类中的为什么把基类中的show()show()函数定义为虚函数时函数定义为虚函数时,程程序的运行结果就正确了呢?序的运行结果就正确了呢?这是因为这是因为,关键字关键字virtualvirtual指示指示C+C+编译器编译器,使用语使用语句句“mp-show()mp-show()”调用虚函数时调用虚函数时,采用采用动态联编动态联编的方式,的方式,即在运行时确定调用哪个即在运行时确定调用哪个show()show()函数。函数。我们把使用同一种调用形式我们把使用同一种调用形式“mp-show()mp-show()”,调,调用用同一类族同一类族中不同类的虚函数称为中不同类的虚函数称为动态的多态性动态的多态性,即,即运行时的多态性运行时的多态性。可见,虚函数与派生类的结合可使可见,虚函数与派生类的结合可使C+C+支持支持运行时运行时的多态性的多态性。2.虚函数的定义 定义虚函数的格式如下:重新定义虚函数时重新定义虚函数时,要求:要求:该函数与基类的虚函数有该函数与基类的虚函数有相同的名称相同的名称;该函数与基类的虚函数有该函数与基类的虚函数有相同的参数个数及相同的对应参相同的参数个数及相同的对应参数类型数类型;该函数与基类的虚函数有该函数与基类的虚函数有相同的返回类型相同的返回类型或者满足赋值兼或者满足赋值兼容规则的指针、引用型的返回类型。容规则的指针、引用型的返回类型。virtual virtual 函数类型函数类型 函数名函数名(形参表形参表)函数体函数体#include/例例6.3虚函数的定义举例。虚函数的定义举例。usingnamespacestd;classGrandam/声明基类声明基类Grandampublic:virtualvoidintroduce_self()/定义虚函数定义虚函数introduce_selfcoutIamgrandam.endl;classMother:publicGrandam/声明派生类声明派生类Motherpublic:voidintroduce_self()/重新定义虚函数重新定义虚函数introduce_selfcoutIammother.endl;classDaughter:publicMother/声明派生类声明派生类Daughterpublic:voidintroduce_self()/重新定义虚函数重新定义虚函数introduce_selfcoutIamdaughter.introduce_self();/调用基类调用基类Grandam的虚函数的虚函数ptr=&m;/对象指针对象指针ptr指向派生类对象指向派生类对象mptr-introduce_self();/调用派生类调用派生类Mother的虚函数的虚函数ptr=&d;/对象指针对象指针ptr指向派生类对象指向派生类对象dptr-introduce_self();/调用派生类调用派生类Daughter的虚函数的虚函数return0;本程序运行的结果如下本程序运行的结果如下:Iamgrandam.Iammother.Iamdaughter.说明:说明:(1)(1)通过定义虚函数来使用多态性机制时,派生类必须通过定义虚函数来使用多态性机制时,派生类必须从它的基类从它的基类公有派生公有派生。(2)(2)在基类中在基类中,声明虚函数原型声明虚函数原型(需加上需加上virtual)virtual),而在,而在类外定义虚函数时类外定义虚函数时,则不必再加则不必再加virtualvirtual。例如:。例如:classB0public:virtualvoidprint(char*p);voidB0:print(char*p)coutpprint()endl;在类外在类外,定义虚函数时定义虚函数时,不要加不要加virtualvirtual 声明虚函数原型声明虚函数原型,需加上需加上virtualvirtual (3)(3)如果在派生类中没有对基类的虚函数重新定义如果在派生类中没有对基类的虚函数重新定义,则则公有派生类公有派生类继承其直接基类的虚函数。一个虚函数无论被公继承其直接基类的虚函数。一个虚函数无论被公有继承多少次有继承多少次,它仍然保持其虚函数的特性。它仍然保持其虚函数的特性。例如例如:class B0class B0 .public:public:virtual void show().virtual void show().;class B1:public B0class B1:public B0 .;若在公有派生类若在公有派生类B1B1中没有重中没有重新定义虚函数新定义虚函数show,show,则函数则函数showshow在派生类中被继在派生类中被继承承,仍是虚函数。仍是虚函数。在基类在基类B0B0中中,定义定义showshow为虚函数为虚函数 (4)(4)在派生类中重新定义该虚函数时在派生类中重新定义该虚函数时,关键字关键字virtualvirtual可以可以写也可以不写。写也可以不写。但是但是,为了使程序更加清晰为了使程序更加清晰,最好在每一层最好在每一层派生类中定义该函数时都加上关键字派生类中定义该函数时都加上关键字virtualvirtual。class B0class B0 .public:public:virtual virtual void show().void show().;class B1:public B0class B1:public B0 .virtual virtual void show().void show().;(5)(5)虽然使用虽然使用对象名和点运算符对象名和点运算符的方式也可以调用虚函数的方式也可以调用虚函数,但是这种调用是在编译时进行的但是这种调用是在编译时进行的,是静态联编是静态联编,它没有利用虚它没有利用虚函数的特性。函数的特性。只有通过只有通过基类指针访问虚函数时基类指针访问虚函数时才能获得运行时的多态才能获得运行时的多态性。性。在基类在基类B0B0中中,定义定义showshow为虚函数为虚函数 在在派派生生类类中中,重重新新定定义义虚虚函函数数show()show()时时,最最好好也也加加上上关关键键字字virtualvirtual#include/例例classbaseinta,b;public:base(intx,inty)a=x;b=y;virtualvoidshow()cout调用基类调用基类base的的show函数函数n;couta=ab=bendl;classdirive:publicbaseintc;public:dirive(intx,inty,intz):base(x,y)c=z;voidshow()cout调用派生类调用派生类dirive的的show函数函数n;coutc=cendl;voidmain()basemb(50,50);dirivemc(10,20,30);mb.show();mc.show();使用使用”mb.showmb.show();();”的方式调的方式调用基类用基类basebase的的showshow函数函数使用使用”mc.showmc.show();();”的方式调用的方式调用派生类派生类dirivedirive的的showshow函数函数程序运行结果如下:程序运行结果如下:调用基调用基类类basebase的的showshow函数函数a=50 b=50a=50 b=50调用派生类调用派生类dirivedirive的函数的函数c=30c=30 这种调用是在这种调用是在编译时进行的编译时进行的,是静态联编是静态联编 (6)(6)虚函数虚函数必须是其所在类的必须是其所在类的成员函数成员函数,而不能是而不能是友元函数友元函数,也不能是静态成员函数也不能是静态成员函数,因为虚函数调用要靠因为虚函数调用要靠特定的对象来决定该激活哪个函数。特定的对象来决定该激活哪个函数。(7)(7)内联函数内联函数不能是虚函数,因为内联函数是不能不能是虚函数,因为内联函数是不能在运行中动态确定其位置的。即使虚函数在类的内部定在运行中动态确定其位置的。即使虚函数在类的内部定义,编译时仍将其看作是非内联的。义,编译时仍将其看作是非内联的。(8)(8)构造函数构造函数不能是虚函数,但是不能是虚函数,但是析构函数析构函数可以是可以是虚函数虚函数,而且通常说明为虚函数。,而且通常说明为虚函数。6.2.3 6.2.3 虚析构函数虚析构函数#include/例例6.4-1虚析构函数的引例虚析构函数的引例1。usingnamespacestd;classBasepublic:Base()cout调用基类调用基类Base的析构函数的析构函数n;classDerived:publicBasepublic:Derived()cout调用派生类调用派生类Derived的析构函数的析构函数n;intmain()Derivedobj;return0;程序运行的结果为程序运行的结果为:调用派生类调用派生类DerivedDerived的析构函数的析构函数调用基类调用基类BaseBase的析构函数的析构函数#include/例例6.5-1虚析构函数的引例虚析构函数的引例2。usingnamespacestd;classBpublic:B()cout调用基类调用基类B的析构函数的析构函数n;classD:publicBpublic:D()cout调用派生类调用派生类D的析构函数的析构函数n;intmain()B*p;/定义指向基类定义指向基类B的指针变量的指针变量pp=newD;deletep;return0;用运算符用运算符newnew为派生类的无名对为派生类的无名对象动态地象动态地 分配了一个存储空间分配了一个存储空间,并将地址赋给对象指针并将地址赋给对象指针p p用用deletedelete撤销无名对象撤销无名对象,释放动态存储空间释放动态存储空间程序运行的结果为程序运行的结果为:调用基类调用基类B B的析构函数的析构函数 本程序本程序只执行了基类只执行了基类B B的析构函数的析构函数,而没有执行而没有执行派生类派生类D D的析构函数。原因是当撤销指针的析构函数。原因是当撤销指针P P所指的所指的派生类的无名对象派生类的无名对象,调用析构函数时调用析构函数时,采用了采用了静静态联编方式态联编方式,只调用了基类只调用了基类B B的析构函数。的析构函数。#include/例例6.6-1虚析构函数的使用虚析构函数的使用。usingnamespacestd;classBpublic:virtualB()cout调用基类调用基类B的析构函数的析构函数n;classD:publicBpublic:D()cout调用派生类调用派生类D的析构函数的析构函数n;intmain()B*p;/定义指向基类定义指向基类B的指针变量的指针变量pp=newD;deletep;return0;用运算符用运算符newnew为派生类的无名对为派生类的无名对象动态地象动态地 分配了一个存储空间分配了一个存储空间,并将地址赋给对象指针并将地址赋给对象指针p p用用deletedelete撤销无名对象撤销无名对象,释放动态存储空间释放动态存储空间程序运行的结果为程序运行的结果为:调用派生类调用派生类D D的析构函数的析构函数调用基类调用基类B B的析构函数的析构函数 将将中基类的中基类的析构函数声明为析构函数声明为虚析构函数虚析构函数 使用了虚析构函使用了虚析构函数数,程序执行了程序执行了动态联编动态联编,实现了实现了运行的多态性运行的多态性。声明虚析构函数的一般格式为声明虚析构函数的一般格式为:说明:说明:(1)(1)虚析构函数虚析构函数没有类型没有类型,也也没有参数没有参数。(2)2)如果将基类的析构函数定义为虚函数如果将基类的析构函数定义为虚函数,由该基由该基类所派生的类所派生的所有派生类的析构函数也都自动成为虚函所有派生类的析构函数也都自动成为虚函数。数。(3)(3)在在C+C+中中,不能声明虚构造函数不能声明虚构造函数,但是可以声明虚但是可以声明虚析构函数。析构函数。virtual类名类名();函数体函数体6.2.4 6.2.4 虚函数与重载函数的关系虚函数与重载函数的关系 (1)(1)在一个派生类中重新定义虚函数是函数重载在一个派生类中重新定义虚函数是函数重载的另一种形式,但它不同于一般的函数重载。的另一种形式,但它不同于一般的函数重载。(2)2)当普通的当普通的函数重载函数重载时,其函数的时,其函数的参数个数参数个数或或参数类型参数类型必须有所不同必须有所不同,函数的返回类型也可以不同。,函数的返回类型也可以不同。但是,当重载一个但是,当重载一个虚函数虚函数时,要求时,要求函数名函数名、返回返回类型类型、参数个数参数个数、参数的类型和顺序参数的类型和顺序与基类中的虚函与基类中的虚函数原型数原型完全相同完全相同。(3)当重载一个虚函数时当重载一个虚函数时,如果仅仅返回类型不同,如果仅仅返回类型不同,其余均相同,系统会给出错误信息;其余均相同,系统会给出错误信息;例如:例如:classbasepublic:virtualvoidf3();classderived:publicbasepublic:charf3();两个函数两个函数f3()f3()仅仅返回类仅仅返回类型不同型不同,将给出错误信息。将给出错误信息。(4)若仅仅函数名相同,而参数的个数、类型或顺序若仅仅函数名相同,而参数的个数、类型或顺序不同,系统将它作为普通的函数重载,这时将失去虚函不同,系统将它作为普通的函数重载,这时将失去虚函数的特性。数的特性。例如:例如:classbasepublic:virtualvoidf2();classderived:publicbasepublic:voidf2(intx);两个函数两个函数f2f2()()函数名相同,函数名相同,但参数的个数但参数的个数和类型不同,和类型不同,作为普通的函作为普通的函数重载数重载,这时,这时将失去虚函数将失去虚函数的特性。的特性。#include/例例6.7-1classbasepublic:virtualvoidfunc1();virtualvoidfunc2();virtualvoidfunc3();voidfunc4();classderived:publicbasepublic:voidfunc1();/是虚函数,这里可不写是虚函数,这里可不写virtualvoidfunc2(intx);/作为普通函数重载,虚特性消失作为普通函数重载,虚特性消失charfunc3();voidfunc4();/是普通函数重载,不是虚函数是普通函数重载,不是虚函数voidbase:func1()cout-basefunc1-n;voidbase:func2()cout-basefunc2-n;voidbase:func3()cout-basefunc3-n;/voidbase:func4()cout-basefunc4-n;voidderived:func1()cout-derivedfunc1-n;voidderived:func2(intx)coutderivedfunc2n;voidderived:func4()cout-derivedfunc4-n;错误错误,因为与基因为与基类中的类中的func3func3只有返只有返回类型不同回类型不同#includeclassbasepublic:virtualvoidfunc1();virtualvoidfunc2();voidfunc4();classderived:publicbasepublic:voidfunc1();/是虚函数,这里可不写是虚函数,这里可不写virtualvoidfunc2(intx);/作为普通函数重载,虚特性消失作为普通函数重载,虚特性消失voidfunc4();/是普通函数重载,不是虚函数是普通函数重载,不是虚函数voidbase:func1()cout-basefunc1-n;voidbase:func2()cout-basefunc2-n;voidbase:func4()cout-basefunc4-n;voidderived:func1()cout-derivedfunc1-n;voidderived:func2(intx)coutderivedfunc2n;voidderived:func4()coutfunc1();-func1();bpbp-func2();-func2();bpbp-func4();-func4();程序执行结果如下:程序执行结果如下:-derived func1-derived func1-base func2-base func2-base func4-base func46.2.5 6.2.5 多继承与虚函数多继承与虚函数 多重继承可以视为多个单继承的组合。因此,多重继承可以视为多个单继承的组合。因此,多多重继承情况下的虚函数的调用与单继承情况下的虚函重继承情况下的虚函数的调用与单继承情况下的虚函数的调用有相似之处。数的调用有相似之处。#include /例例6.8-1 class A1 public:virtual void f()cout“-A1-n;class A2 public:void f()cout-A2-n;class B:public A1,public A2 public:void f()coutf();/调用基类调用基类A1A1的的f()f()ptr2=&obj2;ptr2-f();/调用基类调用基类A2A2的的f()f()ptr1=&obj3;ptr1-f();ptr2=&obj3;ptr2-f();此处调用的此处调用的f()f()为非虚函为非虚函数,因此调用基类数,因此调用基类B B的的f()f()此处调用的此处调用的f()f()为虚函数,为虚函数,因此调用派生类因此调用派生类B B的的f()f()虚函数虚函数 非虚函数,普通非虚函数,普通的成员函数的成员函数对虚函数进行重定义对虚函数进行重定义运行结果运行结果:-A1-A1-A2-A2-B-B-A2-A2-6.3 纯虚函数和抽象类 6.3.1 纯虚函数的引例 1.纯虚函数的引例 例6.9-1 应用C+的虚函数,计算三角形、矩形和圆的面积。圆类圆类 CircleCircle虚函数虚函数area()area()三角形类三角形类Triangle Triangle 虚函数虚函数area()area()矩形类矩形类SquareSquare虚函数虚函数area()area()基类基类FigureFigure 虚函数虚函数 area()area()classFigureprotected:doublex,y;public:Figure(doublea,doubleb)x=a;y=b;virtualvoidarea()cout在基类中定义的虚函数在基类中定义的虚函数n;定义一个公共基类定义一个公共基类FigureFigure 定义虚函数定义虚函数area()area(),为派生类提供一个公,为派生类提供一个公共接口共接口,以便派生类根据需要重新定义虚函数。以便派生类根据需要重新定义虚函数。classTriangle:publicFigurepublic:Triangle(doublea,double):Figure(a,b)voidarea()cout三角形的高是三角形的高是x,底是,底是y;cout,面积是,面积是0.5*x*yendl;虚函数虚函数area()area()重新定义,重新定义,用作求三角形的面积用作求三角形的面积定义三角形派生定义三角形派生TriangleTriangleclassSquare:publicFigurepublic:Square(doublea,doubleb):Figure(a,b)voidarea()cout矩形的长是矩形的长是x,宽是,宽是y;cout,面积是,面积是x*yendl;虚函数虚函数area()area()重新定重新定义,用作求矩形的面积义,用作求矩形的面积 定义矩形派生类定义矩形派生类SquareSquareclassCircle:publicFigurepublic:Circle(doublea):Figure(a,a)voidarea()cout圆的半径是圆的半径是x;cout,面积是,面积是3.1416*x*xarea();p=&s;p-area();p=&c;p-area();return0;计算三角形的面积计算三角形的面积计算矩形的面积计算矩形的面积计算圆的面积计算圆的面积2.纯虚函数纯虚函数classFigureprotected:doublex,y;public:Figure(doublea,doubleb)x=a;y=b;virtualvoidarea()cout在基类中定义的虚函数在基类中定义的虚函数n;基类本身并不需要这个虚函基类本身并不需要这个虚函数,而是数,而是为派生类提供一个为派生类提供一个公共公共接口接口,以便派生类根据需要重新以便派生类根据需要重新定义虚函数。定义虚函数。classFigureprotected:doublex,y;public:Figure(doublea,doubleb)x=a;y=b;virtualvoidarea()=0;将函数将函数area()area()简化简化表示成这种形式表示成这种形式 纯虚函数纯虚函数纯虚函数是在声明虚函数时被纯虚函数是在声明虚函数时被“初始化初始化”为为0 0的虚函数。的虚函数。纯纯虚虚函函数数的的作作用用是是在在基基类类中中为为其其派派生生类类保保留留一一个个函数的名字函数的名字,以便派生类根据需要对它进行重新定义。以便派生类根据需要对它进行重新定义。纯虚函数的特点:纯虚函数的特点:纯虚函数纯虚函数没有函数体没有函数体;最最后后面面的的“=0=0”并并不不表表示示函函数数的的返返回回值值为为0 0,它它只只起起形形式式上上的的作作用用,告告诉诉编编译译系系统统“这这是是纯纯虚虚函函数数”;纯虚函数不具备函数的功能,纯虚函数不具备函数的功能,不能被调用不能被调用。纯虚函数的一般形式如下:纯虚函数的一般形式如下:virtual virtual 函数类型函数类型 函数名函数名(参数表参数表)=0)=0;例例6.9-2使用纯虚函数的例子。使用纯虚函数的例子。#includeclassCircleprotected:intr;public:voidsetr(intx)r=x;virtualvoidshow()=0;classArea:publicCirclepublic:voidshow()cout这个圆的面积是这个圆的面积是:3.14*r*rendl;classPerimeter:publicCirclepublic:voidshow()cout这个圆的周长是这个圆的周长是:2*3.14*rshow();-show();ptrptr=&ob2;=&ob2;ptrptr-show();-show();程序运行结果如下程序运行结果如下:这个圆的面积是这个圆的面积是:314:314这个圆的周长是这个圆的周长是:62.8:62.86.3.2.抽象类抽象类什么是抽象类什么是抽象类?如果一个类如果一个类至少有一个纯虚函数至少有一个纯虚函数,那么就称该类为,那么就称该类为抽象类。抽象类。classFigureprotected:doublex,y;public:Figure(doublea,doubleb)x=a;y=b;virtualvoidarea()=0;纯虚函数纯虚函数抽象类抽象类 抽象类的作用抽象类的作用 抽象类的作用是作为一个类族的抽象类的作用是作为一个类族的共同基类共同基类,相关,相关的派生类是从这个基类派生出来的。的派生类是从这个基类派生出来的。使用抽象类的几点规定使用抽象类的几点规定 (1)(1)由于抽象类中至少包含有一个没有定义功能由于抽象类中至少包含有一个没有定义功能的纯虚函数的纯虚函数,因此抽象类只能用作其他类的基类因此抽象类只能用作其他类的基类,不能建立抽象不能建立抽象类对象。类对象。(2)(2)不允许从具体类派生出抽象类。所谓具体类,不允许从具体类派生出抽象类。所谓具体类,就是不包含纯

    注意事项

    本文(6 多态性与虚函数.ppt)为本站会员(hwp****526)主动上传,淘文阁 - 分享文档赚钱的网站仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知淘文阁 - 分享文档赚钱的网站(点击联系客服),我们立即给予删除!

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




    关于淘文阁 - 版权申诉 - 用户使用规则 - 积分规则 - 联系我们

    本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

    工信部备案号:黑ICP备15003705号 © 2020-2023 www.taowenge.com 淘文阁 

    收起
    展开