面向对象程序设计语言C++第2版 教学课件 ppt 作者 陈文宇 面向对象程序设计语言C++ - 第7章 虚函数和多态性

上传人:E**** 文档编号:89331676 上传时间:2019-05-23 格式:PPT 页数:34 大小:640KB
返回 下载 相关 举报
面向对象程序设计语言C++第2版 教学课件 ppt 作者 陈文宇 面向对象程序设计语言C++ - 第7章 虚函数和多态性_第1页
第1页 / 共34页
面向对象程序设计语言C++第2版 教学课件 ppt 作者 陈文宇 面向对象程序设计语言C++ - 第7章 虚函数和多态性_第2页
第2页 / 共34页
面向对象程序设计语言C++第2版 教学课件 ppt 作者 陈文宇 面向对象程序设计语言C++ - 第7章 虚函数和多态性_第3页
第3页 / 共34页
面向对象程序设计语言C++第2版 教学课件 ppt 作者 陈文宇 面向对象程序设计语言C++ - 第7章 虚函数和多态性_第4页
第4页 / 共34页
面向对象程序设计语言C++第2版 教学课件 ppt 作者 陈文宇 面向对象程序设计语言C++ - 第7章 虚函数和多态性_第5页
第5页 / 共34页
点击查看更多>>
资源描述

《面向对象程序设计语言C++第2版 教学课件 ppt 作者 陈文宇 面向对象程序设计语言C++ - 第7章 虚函数和多态性》由会员分享,可在线阅读,更多相关《面向对象程序设计语言C++第2版 教学课件 ppt 作者 陈文宇 面向对象程序设计语言C++ - 第7章 虚函数和多态性(34页珍藏版)》请在金锄头文库上搜索。

1、面向对象程序设计语言C+,电子科技大学示范性软件学院,1,第七章 虚函数和多态性,现实生活中,经常出现这种情况:面对同样的消息,不同的人,面对同样的消息,产生不同的反应。 面向对象语言是解决现实世界问题的,也需要对这种实际情况进行处理。C+程序设计语言使用多态性实现同一个消息,不同接收者采取不同的响应方式的这种现象。 顾名思义,多态性是一个事务有多种形态。在面向对象语言中,一般这样描述多态:向不同对象发送同一个消息,不同的对象在接收时会产生不同的行为(即方法)。也就是说,每个对象可以用自己的方式去响应共同的消息。,2,第七章 虚函数和多态性,C+语言的多态性有两种类型:静态多态性和动态多态性。

2、前面学习的函数重载和运算符重载就是静态多态性的具体示例。在程序编译时系统就能够决定调用哪个函数,因此静态多态性又称为编译时的多态性。动态多态性时程序运行过程中才动态的确定操作所针对的对象。它又称为运行时的多态性。动态多态性是通过虚函数实现的。,3,第七章 虚函数和多态性,7.1 虚函数 7.1.1静态多态性 对于普通成员函数的重载,可表达为下面的方式: (1)在同一个类中重载; (2)在不同类中重载; (3)基类的成员函数在派生类中重载; 因此,重载函数的访问是在编译时区分的,这种程序运行之前就能够在多个函数中确定当前访问的函数的方法称为静态多态性。,4,第七章 虚函数和多态性,7.1 虚函数

3、 7.1.1静态多态性 有以下三种区分方法: 据参数的特征加以区分,例如: Show(int, char) 与 Show(char * , float) 使用”:”加以区分,例如: Circle : Show 有别于 Point : Show 根据类对象加以区分 ACircle.Show() 调用 Circle : Show(),5,第七章 虚函数和多态性,7.1 虚函数 7.1.1静态多态性 子类可以重载父类的成员: class A public: void fun() cout“In A“endl; ; class B : public A public: void fun() cout“

4、In B“endl; ;,6,第七章 虚函数和多态性,7.1 虚函数 7.1.1静态多态性 C Cobj; Cobj.fun(); /调用C:fun() Cobj.B:fun(); /调用B:fun() Cobj.A:fun(); /调用A:fun() A /调用A:fun(),7,第七章 虚函数和多态性,7.1 虚函数 7.1.2基类和派生类的指针与对象的关系 (1)可以用一个指向基类的指针指向其公有派生类的对象。这时,基类指针访问的是派生对象的拥有的基类部分,派生类自身的部分不能被基类指针访问。但是用指向派生类的指针指向一个基类的对象是不正确的,因为派生类指针可以访问派生类公有成员,但基类

5、对象没有派生类自身成员,因此用派生类指针指向基类对象时,如果访问派生类公有成员,而该成员实际不存在,所以不能用指向派生类的指针指向一个基类的对象。 (2)希望用基类指针访问其公有派生类的特定成员,必须将基类指针用显示类型转换为派生类指针。,8,第七章 虚函数和多态性,7.1 虚函数 7.1.3 虚函数与多态性 1虚函数的概念 一个指向基类的指针可用来指向从基类公有派生的任何对象,这一事实是非常重要的,是 C+ 实现运行时多态性的关键途径。如果有多个或者多层派生类,通过一个基类指针可以访问所有派生类对象的成员函数,这样就可以实现一个接口,多个实现的访问了。但是观察例73,基类指针能否访问不同派生

6、类对象的成员函数呢?,9,第七章 虚函数和多态性,7.1 虚函数 7.1.3 虚函数与多态性 class Base public: Base(int a) x=a; void who() cout “base “x“n“; protected: int x; ;,10,class First_d: public Base public: First_d (int a ):Base(a) void who() cout “First derivation “ x“n“; ; class Second_d :public Base public: Second_d (int a):Base(a)

7、void who() cout “Second derivation “ x“n“; ;,第七章 虚函数和多态性,7.1 虚函数 7.1.3 虚函数与多态性 Base * p; Base base_obj(1); First_d first_obj(2); Second_d second_obj(3); p= 请问程序的输出是什么?,11,第七章 虚函数和多态性,7.1 虚函数 7.1.3 虚函数与多态性 程序的输出是: base 1 base 2 base 3 很奇怪,是吗?明明是指向子类的指针,为什么调用的却是父类的函数版本呢?,12,第七章 虚函数和多态性,7.1 虚函数 7.1.3 虚

8、函数与多态性 答案很简单,因为通过父类指针来看,该指针所指向的是一个父类对象。,13,第七章 虚函数和多态性,7.1 虚函数 7.1.3 虚函数与多态性 如果随着p所指向的对象的不同p-who()能调用不同类中who()的版本,这样就可以用一个界面p-who()访问多个实现版本,这在编程时非常有用。实际上,这表达了一种动态的性质,函数调用p-who()依赖于运行时p所指向的对象。虚函数提供的就是这种解释机制。虚函数是在基类中被冠以virtual的成员函数,它提供了一种接口界面。,14,第七章 虚函数和多态性,7.1 虚函数 7.1.3 虚函数与多态性 虚函数可以在一个或多个派生类中被重新定义,

9、但要求在派生类中重新定义时,虚函数的函数原型,包括返回类型,函数名,参数个数,参数类型的顺序,必须完全相同。 前面的程序修改为下页所示就能达到目的。,15,第七章 虚函数和多态性,7.1 虚函数 7.1.3 虚函数与多态性 class Base public: Base(int a) x=a; virtual void who() cout “base “x“n“; protected: int x; ;,16,class First_d: public Base public: First_d (int a ):Base(a) void who() cout “First derivatio

10、n “ x“n“; ; class Second_d :public Base public: Second_d (int a):Base(a) void who() cout “Second derivation “ x“n“; ; (例7-4),第七章 虚函数和多态性,7.1 虚函数 2运行时的多态性与虚特性 (1)运行时的多态性 晚期匹配如何发生?所有的工作都由编译器在幕后完成。当我们告诉它去晚期匹配(用创建虚函数告诉它),编译器安装必要的晚期匹配机制。关键字virtual告诉编译器它不应当完成早期匹配,相反,它应当自动安装实现晚期匹配所必须的所有机制。 那么,编译器会怎么做呢?请先看一

11、个例子。,17,第七章 虚函数和多态性,7.1 虚函数 class NoVirtual int i; public: void f(); ;,18,class OneVirtual int i; public: void f(); virtual void g(); ;,class TwoVirtual int i; public: void f(); virtual void g(); virtual void h(); ;,第七章 虚函数和多态性,7.1 虚函数 int main() cout “size of int: “ sizeof(int) endl; cout “size of

12、pointer: “ sizeof(void *) endl; cout “size of NoVirtual: “ sizeof(NoVirtual) endl; cout “size of OneVirtual: “ sizeof(OneVirtual) endl; cout “size of TwoVirtual: “ sizeof(TwoVirtual) endl; return 0; ,19,第七章 虚函数和多态性,7.1 虚函数 假设这个程序的编译环境和运行环境都是32位的,那么请问程序的输出是什么?,20,程序的输出如下: size of int:4 size of pointe

13、r:4 size of NoVirtual:4 size of OneVirtual:8 size of TwoVirtual:8 很奇怪,是吗?拥有虚函数的类尺寸多了4个字节。,第七章 虚函数和多态性,7.1 虚函数 很明显,这是4个字节是编译器插入到类中的。那么它是什么呢? 在每个带有虚函数的类中,编译器秘密地置一指针,称为虚指针vpointer(缩写为VPTR)。此外,编译器对每个包含虚函数的类创建一个虚表(称为VTABLE)。在VTABLE中,编译器放置特定类的虚函数地址。VPTR指向这个对象的VTABLE。通过基类指针做虚函数调用时(也就是做多态调用时),编译器取得这个VPTR,找到

14、该类的VTABLE,并在其中查找相应虚函数地址,这样就能调用正确的函数,使晚捆绑发生。,21,第七章 虚函数和多态性,7.1 虚函数,22,第七章 虚函数和多态性,7.1 虚函数 一个成员函数什么时候需要声明为虚函数呢?主要考虑以下几点: 首先考虑成员函数所在的类是否会做为基类。然后看成员函数在类的继承后有无功能被修改?如果希望修改其功能,一般将它声明为虚函数。 还应当考虑对成员函数的调用是通过对象名还是基类指针或引用去访问。如果通过基类指针或引用去访问,则声明为虚函数。 如果希望通过基类指针或者引用访问派生类成员函数,但基类功能比较抽象或者不能确定功能,可以将基类定义为抽象类,即只定义函数名

15、字,没有函数体,具体功能由派生类添加。,23,第七章 虚函数和多态性,7.1 虚函数 (2)虚特性 用虚函数实现运行时多态性的关键之处是,必须用指向基类的指针(或者引用)访问虚函数。尽管可以像调用其他成员函数那样显式地用对象名来调用一个虚函数,但只有在一个指向基类的指针(或者引用)访问虚函数时,运行时多态性才能实现。这时,称为函数具有虚特性。,24,第七章 虚函数和多态性,7.1 虚函数 基类函数具有虚特性的条件是: 在基类中,将该函数说明为虚(virtual)函数。这样可以在派生类中重新定义此函数,为它赋予新的功能,并能够方便调用。在类外定义虚函数时,不必再加virtual关键字。 定义基类

16、的公有派生类; 在基类的公有派生类中原型一致地重载该虚函数; 定义指向基类的指针变量,它指向基类的公有派生类的对象(或定义基类的引用,它引用基类的公有派生类的对象)。,25,第七章 虚函数和多态性,7.1 虚函数 重载一个虚函数时,要求函数名、返回类型、参量个数、参数类型和顺序是完全相同的。如果不同,会产生什么情况呢? (1)仅仅返回类型不同,其余相同。C+认为这是错误的,因为仅仅返回类型不同的函数本质上是含糊的。 (2)函数原型不同,仅函数名相同,C+认为这是一般的函数重载,此时虚特性丢失。(例7-5),26,第七章 虚函数和多态性,7.1 虚函数 定义虚函数时需要注意: (1) 虚函数必须是类的成员函数。不能将虚函数说明为全局(非成员的)函数,也不能说明为静态成员函数。不能将友元说明为虚函数,但虚函数可以是另一个类的友元。 (2) 析构函数可以

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 高等教育 > 大学课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号