版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
面向对象程序设计语言虚函数和多态性详解演示文稿第一页,共29页。优选面向对象程序设计语言虚函数和多态性第二页,共29页。第七章虚函数和多态性C++语言的多态性有两种类型:静态多态性和动态多态性。前面学习的函数重载和运算符重载就是静态多态性的具体示例。在程序编译时系统就能够决定调用哪个函数,因此静态多态性又称为编译时的多态性。动态多态性时程序运行过程中才动态的确定操作所针对的对象。它又称为运行时的多态性。动态多态性是通过虚函数实现的。3第三页,共29页。第七章虚函数和多态性7.1虚函数7.1.1静态多态性对于普通成员函数的重载,可表达为下面的方式:(1)在同一个类中重载;(2)在不同类中重载;(3)基类的成员函数在派生类中重载;因此,重载函数的访问是在编译时区分的,这种程序运行之前就能够在多个函数中确定当前访问的函数的方法称为静态多态性。4第四页,共29页。第七章虚函数和多态性7.1虚函数7.1.1静态多态性有以下三种区分方法:据参数的特征加以区分,例如:Show(int,
char)与
Show(char*,
float)使用”::”加以区分,例如:Circle::Show有别于
Point::Show根据类对象加以区分ACircle.Show()调用
Circle::Show()5第五页,共29页。第七章虚函数和多态性7.1虚函数7.1.1静态多态性子类可以重载父类的成员:classA{public: voidfun()
{cout<<"InA"<<endl;}};classB
:
publicA{public: voidfun()
{cout<<"InB"<<endl;}};6第六页,共29页。第七章虚函数和多态性7.1虚函数7.1.1静态多态性
CCobj; Cobj.fun();
//调用C::fun() Cobj.B::fun();//调用B::fun() Cobj.A::fun();//调用A::fun() A&Aref=Cobj; Aref.fun();
//调用A::fun(),编译器通过类型确定调用哪个版本
B&Bref=Cobj; Bref.fun();
//调用B::fun() Bref.B::fun();//调用B::fun() A*Apointer=&Cobj; Apointer->fun();//调用A::fun()7第七页,共29页。第七章虚函数和多态性7.1虚函数7.1.2基类和派生类的指针与对象的关系(1)可以用一个指向基类的指针指向其公有派生类的对象。这时,基类指针访问的是派生对象的拥有的基类部分,派生类自身的部分不能被基类指针访问。但是用指向派生类的指针指向一个基类的对象是不正确的,因为派生类指针可以访问派生类公有成员,但基类对象没有派生类自身成员,因此用派生类指针指向基类对象时,如果访问派生类公有成员,而该成员实际不存在,所以不能用指向派生类的指针指向一个基类的对象。(2)希望用基类指针访问其公有派生类的特定成员,必须将基类指针用显示类型转换为派生类指针。8第八页,共29页。第七章虚函数和多态性7.1虚函数7.1.3虚函数与多态性1.虚函数的概念
一个指向基类的指针可用来指向从基类公有派生的任何对象,这一事实是非常重要的,是
C++实现运行时多态性的关键途径。如果有多个或者多层派生类,通过一个基类指针可以访问所有派生类对象的成员函数,这样就可以实现一个接口,多个实现的访问了。但是观察例7-3,基类指针能否访问不同派生类对象的成员函数呢?9第九页,共29页。第七章虚函数和多态性7.1虚函数7.1.3虚函数与多态性classBase{public: Base(inta) {x=a;} voidwho() {cout<<"base"<<x<<"\n";}protected: intx;};10classFirst_d:publicBase{public:First_d(inta):Base(a)
{}
voidwho()
{cout<<"Firstderivation"<<x<<"\n";}};classSecond_d:publicBase{public:
Second_d(inta):Base(a)
{}
voidwho()
{cout<<"Secondderivation"<<x<<"\n";}};第十页,共29页。第七章虚函数和多态性7.1虚函数7.1.3虚函数与多态性
Base*p; Basebase_obj(1); First_dfirst_obj(2); Second_dsecond_obj(3); p=&base_obj; p->who(); p=&first_obj; p->who(); p=&second_obj; p->who();请问程序的输出是什么?11第十一页,共29页。第七章虚函数和多态性7.1虚函数7.1.3虚函数与多态性程序的输出是:base1base2base3很奇怪,是吗?明明是指向子类的指针,为什么调用的却是父类的函数版本呢?12第十二页,共29页。第七章虚函数和多态性7.1虚函数7.1.3虚函数与多态性答案很简单,因为通过父类指针来看,该指针所指向的是一个父类对象。13x&Base::who()&First_d::who()p对于p是不可见的第十三页,共29页。第七章虚函数和多态性7.1虚函数7.1.3虚函数与多态性如果随着p所指向的对象的不同p->who()能调用不同类中who()的版本,这样就可以用一个界面p->who()访问多个实现版本,这在编程时非常有用。实际上,这表达了一种动态的性质,函数调用p->who()依赖于运行时p所指向的对象。虚函数提供的就是这种解释机制。虚函数是在基类中被冠以virtual的成员函数,它提供了一种接口界面。14第十四页,共29页。第七章虚函数和多态性7.1虚函数7.1.3虚函数与多态性虚函数可以在一个或多个派生类中被重新定义,但要求在派生类中重新定义时,虚函数的函数原型,包括返回类型,函数名,参数个数,参数类型的顺序,必须完全相同。前面的程序修改为下页所示就能达到目的。15第十五页,共29页。第七章虚函数和多态性7.1虚函数7.1.3虚函数与多态性classBase{public: Base(inta) {x=a;}
virtualvoidwho() {cout<<"base"<<x<<"\n";}protected: intx;};16classFirst_d:publicBase{public:First_d(inta):Base(a)
{}
voidwho()
{cout<<"Firstderivation"<<x<<"\n";}};classSecond_d:publicBase{public:
Second_d(inta):Base(a)
{}
voidwho()
{cout<<"Secondderivation"<<x<<"\n";}};(例7-4)第十六页,共29页。第七章虚函数和多态性7.1虚函数2.运行时的多态性与虚特性(1)运行时的多态性晚期匹配如何发生?所有的工作都由编译器在幕后完成。当我们告诉它去晚期匹配(用创建虚函数告诉它),编译器安装必要的晚期匹配机制。关键字virtual告诉编译器它不应当完成早期匹配,相反,它应当自动安装实现晚期匹配所必须的所有机制。那么,编译器会怎么做呢?请先看一个例子。17第十七页,共29页。第七章虚函数和多态性7.1虚函数classNoVirtual{inti;public:voidf();};18classOneVirtual{inti;public:voidf();virtualvoidg();};classTwoVirtual{inti;public:voidf();virtualvoidg();virtualvoidh();};第十八页,共29页。第七章虚函数和多态性7.1虚函数intmain(){cout<<"sizeofint:"<<sizeof(int)<<endl;cout<<"sizeofpointer:"<<sizeof(void*)<<endl; cout<<"sizeofNoVirtual:"<<sizeof(NoVirtual)<<endl;cout<<"sizeofOneVirtual:"<<sizeof(OneVirtual)<<endl;cout<<"sizeofTwoVirtual:"<<sizeof(TwoVirtual)<<endl;return0;}19第十九页,共29页。第七章虚函数和多态性7.1虚函数假设这个程序的编译环境和运行环境都是32位的,那么请问程序的输出是什么?20程序的输出如下:sizeofint:4sizeofpointer:4sizeofNoVirtual:4sizeofOneVirtual:8sizeofTwoVirtual:8很奇怪,是吗?拥有虚函数的类尺寸多了4个字节。第二十页,共29页。第七章虚函数和多态性7.1虚函数很明显,这是4个字节是编译器插入到类中的。那么它是什么呢?在每个带有虚函数的类中,编译器秘密地置一指针,称为虚指针vpointer(缩写为VPTR)。此外,编译器对每个包含虚函数的类创建一个虚表(称为VTABLE)。在VTABLE中,编译器放置特定类的虚函数地址。VPTR指向这个对象的VTABLE。通过基类指针做虚函数调用时(也就是做多态调用时),编译器取得这个VPTR,找到该类的VTABLE,并在其中查找相应虚函数地址,这样就能调用正确的函数,使晚捆绑发生。21第二十一页,共29页。第七章虚函数和多态性7.1虚函数22第二十二页,共29页。第七章虚函数和多态性7.1虚函数一个成员函数什么时候需要声明为虚函数呢?主要考虑以下几点:首先考虑成员函数所在的类是否会做为基类。然后看成员函数在类的继承后有无功能被修改?如果希望修改其功能,一般将它声明为虚函数。还应当考虑对成员函数的调用是通过对象名还是基类指针或引用去访问。如果通过基类指针或引用去访问,则声明为虚函数。如果希望通过基类指针或者引用访问派生类成员函数,但基类功能比较抽象或者不能确定功能,可以将基类定义为抽象类,即只定义函数名字,没有函数体,具体功能由派生类添加。23第二十三页,共29页。第七章虚函数和多态性7.1虚函数(2)虚特性用虚函数实现运行时多态性的关键之处是,必须用指向基类的指针(或者引用)访问虚函数。尽管可以像调用其他成员函数那样显式地用对象名来调用一个虚函数,但只有在一个指向基类的指针(或者引用)访问虚函数时,运行时多态性才能实现。这时,称为函数具有虚特性。24第二十四页,共29页。第七章虚函数和多态性7.1虚函数基类函数具有虚特性的条件是:在基类中,将该函数说明为虚(virtual)函数。这样可以在派生类中重新定义此函数,为它赋予新的功能,并能够方便调用。在类外定义虚函数时,不必再加virtual关键字。定义基类的公有派生类;在基类的公有派生类中原型一致地重载该虚函数;定义指向基类的指针变量,它指向基类的公有派生类的对象(或定义基类的引用,它引用基类的公有派生类的对象)。25第二十五页,共29页。第七章虚函数和多态性7.1虚函数重载一个虚函数时,要求函数名、返回类型、参量个数、参数类型和顺序是完全相同的。如果不同,会产生什么情况呢?(1)仅仅返回类型不同,其余相同。C++认为这是错误的,因为仅仅返回类型不同的函数本质上是含糊的。(2)函数原型不同
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- DB32/T 5027-2025老旧曳引驱动乘客电梯安全评估规范
- DB32/T 4808-2024区域现代测绘基准维持与协同服务技术规范
- DB32/T 5138-2025工程建设项目“多测合一”测绘资质单位评价规范
- 高中《人工智能》5篇800字
- 气象局预报岗事业编全真模拟试卷
- 制氢项目可行性研究报告
- 中医内经强化试题及答案解析
- 中外历史人物评说(资料岳麓版)第12课土耳其国父凯末尔
- 人体废物的排出复习
- 医药区域产品经理项目与行动计划制定POA
- 2025年设备监理师职业资格考试(设备工程项目管理)历年参考题库含答案详解
- 2026年部编版新教材道德与法治五年级上册全套教学设计(共4个单元有教学计划)
- DL∕T 2041-2019 分布式电源接入电网承载力评估导则
- 高职应用语文教程(第二版)课件 5平凡的世界(节选)
- 电信渠道建设方案
- 有机绿色蔬菜种植项目立项报告
- 门楣改造施工方案
- 新媒体技术与应用PPT全套完整教学课件
- 乡村振兴战略解读ppt课件-乡村振兴战略课件
- 管理学案例分析管理学题库
- GB/T 25209-2022商品煤标识
评论
0/150
提交评论