6 多态性与虚函数.ppt
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_05.gif)
《6 多态性与虚函数.ppt》由会员分享,可在线阅读,更多相关《6 多态性与虚函数.ppt(56页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、 第第6 6章章 多态性与虚函数多态性与虚函数 6.1 6.1 多态性概述多态性概述 6.2 6.2 虚函数虚函数 6.3 6.3 纯虚函数和抽象类纯虚函数和抽象类在在OOPOOP中:中:窗口对象窗口对象 行为行为3 3 移动移动 同一消息同一消息 棋子对象棋子对象 行为行为4 46.1 6.1 多态性概述多态性概述多态性是面向对象程序设计的重要特征之一。多态性是面向对象程序设计的重要特征之一。多态性是面向对象程序设计的重要特征之一。多态性是面向对象程序设计的重要特征之一。多态性是指多态性是指多态性是指多态性是指发出同样的消息被不同类型的对象接收时导发出同样的消息被不同类型的对象接收时导发出同
2、样的消息被不同类型的对象接收时导发出同样的消息被不同类型的对象接收时导致完全不同的行为。致完全不同的行为。致完全不同的行为。致完全不同的行为。多态的实现:多态的实现:多态的实现:多态的实现:1 1 函数重载函数重载函数重载函数重载2 2 运算符重载运算符重载运算符重载运算符重载3 3 虚函数虚函数虚函数虚函数4 4 类模板类模板类模板类模板 在C+中,多态的实现和联编这一概念有关。所谓联编就是把函数名与函数体的程序代码连接(联系)在一起的过程。静态联编静态联编 联编联编 动态联编动态联编 静态联编就是在编译阶段完成的联编。静态联编就是在编译阶段完成的联编。静态联编静态联编函数调用速度很快。效率
3、高函数调用速度很快。效率高,但缺乏灵活性但缺乏灵活性;动态联编是运行阶段完成的联编。动态联编是运行阶段完成的联编。动态联编在运动态联编在运行时才能确定调用哪个函数行时才能确定调用哪个函数,它降低了程序的运行效率,它降低了程序的运行效率,但增强了程序的灵活性。但增强了程序的灵活性。C+C+实际上是采用了静态联编和动态联编相结合的实际上是采用了静态联编和动态联编相结合的联编方法。联编方法。编译时的多态性编译时的多态性 多态性多态性 运行时的多态性运行时的多态性 编译时的多态是通过编译时的多态是通过静态联编静态联编来实现的。来实现的。运行时的多态是通过运行时的多态是通过动态联编动态联编实现的。实现的
4、。在在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;pu
5、blic: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
6、(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调用调用派生类派生类dirivedi
7、rive的的showshow函数函数c=30c=30程序运行结果如下:程序运行结果如下:调用调用基类基类basebase的的showshow函数函数a=50 b=50a=50 b=50调用调用基类基类basebase的的showshow函数函数a=10 b=20a=10 b=20为为什什么么?在在C+C+中中规规定定:基基类类的的对对象象指指针针可可以以指指向向它它的的公公有有派生的对象派生的对象,但是当其指向公有派生类对象时但是当其指向公有派生类对象时,它只能访问派生类中从基类继承来的成员它只能访问派生类中从基类继承来的成员,而不能访问公有派生类中定义的成员而不能访问公有派生类中定义的成员,
8、例如例如:classApublic:voidprint1().;classB:publicApublic:voidprint2().;voidmain()A*p1;/定义基类定义基类A的指针变量的指针变量p1Bop2;/定义派生类定义派生类B的对象的对象op2p1=&op2;/将指针变量将指针变量p1指向派生类指向派生类对象对象op2p1-print1();p1-print2();正正确确,基基类类指指针针变变量量p1p1可可以以访访问问派派生生类类中中从从基基类类继继承来承来的成员函数的成员函数print1()print1()错误错误,基基类指针变量类指针变量p1p1不能访问不能访问派生类中
9、定派生类中定义义的成员函的成员函数数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-sho
10、w();指指向向基基类类的的指指针针变变量量,当当其其指指向向公公有有派派生生类类对对象象时时,可可以以直直接接访访问问派派生生类类中中从从基基类类继继承承来来的的成成员员,但但不不能能直直接接访访问问公公有有派派生类中定义的成员。生类中定义的成员。不不管管指指向向基基类类对对象象的的指指针针mpmp当当前前指指向向哪哪个个对对象象(基基类类对对象象或或派派生生类类对对象象),mp-show()mp-show()调调用用的的都都是基类中定义的是基类中定义的show()show()。例如:例如:void main()void main()base mb(50,50),*mp;base mb(50
11、,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+中可以用中可以用虚函数虚函数来解决
12、这个问题。来解决这个问题。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:.v
13、oid 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
14、();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=
15、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 voi
16、d 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的的showsho
17、w函数函数c=30c=30调用基类调用基类basebase的的show()show()函数函数调用派生类调用派生类dirivedirive的的show()show()函数函数 为什么把基类中的为什么把基类中的show()show()函数定义为虚函数时函数定义为虚函数时,程程序的运行结果就正确了呢?序的运行结果就正确了呢?这是因为这是因为,关键字关键字virtualvirtual指示指示C+C+编译器编译器,使用语使用语句句“mp-show()mp-show()”调用虚函数时调用虚函数时,采用采用动态联编动态联编的方式,的方式,即在运行时确定调用哪个即在运行时确定调用哪个show()show()
18、函数。函数。我们把使用同一种调用形式我们把使用同一种调用形式“mp-show()mp-show()”,调,调用用同一类族同一类族中不同类的虚函数称为中不同类的虚函数称为动态的多态性动态的多态性,即,即运行时的多态性运行时的多态性。可见,虚函数与派生类的结合可使可见,虚函数与派生类的结合可使C+C+支持支持运行时运行时的多态性的多态性。2.虚函数的定义 定义虚函数的格式如下:重新定义虚函数时重新定义虚函数时,要求:要求:该函数与基类的虚函数有该函数与基类的虚函数有相同的名称相同的名称;该函数与基类的虚函数有该函数与基类的虚函数有相同的参数个数及相同的对应参相同的参数个数及相同的对应参数类型数类型
19、;该函数与基类的虚函数有该函数与基类的虚函数有相同的返回类型相同的返回类型或者满足赋值兼或者满足赋值兼容规则的指针、引用型的返回类型。容规则的指针、引用型的返回类型。virtual virtual 函数类型函数类型 函数名函数名(形参表形参表)函数体函数体#include/例例6.3虚函数的定义举例。虚函数的定义举例。usingnamespacestd;classGrandam/声明基类声明基类Grandampublic:virtualvoidintroduce_self()/定义虚函数定义虚函数introduce_selfcoutIamgrandam.endl;classMother:pub
20、licGrandam/声明派生类声明派生类Motherpublic:voidintroduce_self()/重新定义虚函数重新定义虚函数introduce_selfcoutIammother.endl;classDaughter:publicMother/声明派生类声明派生类Daughterpublic:voidintroduce_self()/重新定义虚函数重新定义虚函数introduce_selfcoutIamdaughter.introduce_self();/调用基类调用基类Grandam的虚函数的虚函数ptr=&m;/对象指针对象指针ptr指向派生类对象指向派生类对象mptr-in
21、troduce_self();/调用派生类调用派生类Mother的虚函数的虚函数ptr=&d;/对象指针对象指针ptr指向派生类对象指向派生类对象dptr-introduce_self();/调用派生类调用派生类Daughter的虚函数的虚函数return0;本程序运行的结果如下本程序运行的结果如下:Iamgrandam.Iammother.Iamdaughter.说明:说明:(1)(1)通过定义虚函数来使用多态性机制时,派生类必须通过定义虚函数来使用多态性机制时,派生类必须从它的基类从它的基类公有派生公有派生。(2)(2)在基类中在基类中,声明虚函数原型声明虚函数原型(需加上需加上virtu
22、al)virtual),而在,而在类外定义虚函数时类外定义虚函数时,则不必再加则不必再加virtualvirtual。例如:。例如:classB0public:virtualvoidprint(char*p);voidB0:print(char*p)coutpprint()endl;在类外在类外,定义虚函数时定义虚函数时,不要加不要加virtualvirtual 声明虚函数原型声明虚函数原型,需加上需加上virtualvirtual (3)(3)如果在派生类中没有对基类的虚函数重新定义如果在派生类中没有对基类的虚函数重新定义,则则公有派生类公有派生类继承其直接基类的虚函数。一个虚函数无论被公继
23、承其直接基类的虚函数。一个虚函数无论被公有继承多少次有继承多少次,它仍然保持其虚函数的特性。它仍然保持其虚函数的特性。例如例如:class B0class B0 .public:public:virtual void show().virtual void show().;class B1:public B0class B1:public B0 .;若在公有派生类若在公有派生类B1B1中没有重中没有重新定义虚函数新定义虚函数show,show,则函数则函数showshow在派生类中被继在派生类中被继承承,仍是虚函数。仍是虚函数。在基类在基类B0B0中中,定义定义showshow为虚函数为虚函数
24、 (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
25、 show().;(5)(5)虽然使用虽然使用对象名和点运算符对象名和点运算符的方式也可以调用虚函数的方式也可以调用虚函数,但是这种调用是在编译时进行的但是这种调用是在编译时进行的,是静态联编是静态联编,它没有利用虚它没有利用虚函数的特性。函数的特性。只有通过只有通过基类指针访问虚函数时基类指针访问虚函数时才能获得运行时的多态才能获得运行时的多态性。性。在基类在基类B0B0中中,定义定义showshow为虚函数为虚函数 在在派派生生类类中中,重重新新定定义义虚虚函函数数show()show()时时,最最好好也也加加上上关关键键字字virtualvirtual#include/例例classba
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 多态性与虚函数 多态性 函数
![提示](https://www.taowenge.com/images/bang_tan.gif)
限制150内