团队学生技术应用交流讲座_第1页
团队学生技术应用交流讲座_第2页
团队学生技术应用交流讲座_第3页
团队学生技术应用交流讲座_第4页
团队学生技术应用交流讲座_第5页
已阅读5页,还剩39页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、团队学生技术应用交流讲座目 录多态性虚函数与动态绑定纯虚函数与抽象类实例讲解习题和课后阅读资料多态性多态性的定义何谓多态性?多态性是指给同样的接口发送同样的消息会导致不同的行为。多态意味着一个对象有着多重特征,可以在特定的情况下,表现不同的状态,从而对应着不同的属性和方法。 多态性是面向对象程序设计的重要特征之一。假设程序设计语言不支持多态性,不能称为面向对象的语言。C+多态性C+有哪些多态性机制?函数重载运算符重载虚函数函数重载和运算符重载是编译时表达出来的多态性,虚函数那么表达了运行时的多态性。虚函数与动态绑定例如:乐器类继承体系类定义Instrument 乐器Wind 管乐器Woodwi

2、nd 木管乐器Brass 铜管乐器Percussion 打击乐器Stringed 弦乐器接口说明play 演奏adjust 调整乐器what 显示乐器信息类型的向上转换(Upcasting)将派生类地址指针或引用沿着继承树向上的方向赋给基类指针(赋值兼容原那么)Upcasting将对象按传址by address而非传值(by value)方式进行操作,而多态性需通过Upcasting来表达。我们想做什么?提供给用户一个通用的不变的系统使用接口函数tune,无论类进行了怎样的变动,这个接口都能正常可靠地工作(总能按照我们的期望选出正确的乐器演奏)我们想做什么?我们的要求是合理的,这种要求系统具备

3、动态识别能力的需求,在实际运行的很多软件系统当中都是一项根本要求,这正是要求系统具备多态性。void tune(Instrument& i) i.play(); int main() Wind flute; tune(flute); / Upcasting 先看一个例子#include using namespace std;enum note middleC, Csharp, Eflat ;.class Instrument public: void play(note) const cout Instrument:play endl; ;/ Wind objects are Instrum

4、ents/ because they have the same interface:class Wind : public Instrument public: / Redefine interface function: void play(note) const cout Wind:play endl; ;void tune(Instrument& i) / . i.play(middleC);int main() Wind flute; tune(flute); / Upcasting return 0; 我们定义了Wind对象flute,通过接口tune操作play函数,显然我们希望

5、flute对象能正确地调用Wind类的play函数运行的结果#include using namespace std;enum note middleC, Csharp, Eflat ;.class Instrument public: void play(note) const cout Instrument:play endl; ;/ Wind objects are Instruments/ because they have the same interface:class Wind : public Instrument public: / Redefine interface fu

6、nction: void play(note) const cout Wind:play endl; ;void tune(Instrument& i) / . i.play(middleC);int main() Wind flute; tune(flute); / Upcasting return 0; 程序却调用了基类Instrument的play函数,显然这不是我们希望的结果!问题出在哪儿了呢?改动一下例子#include using namespace std;enum note middleC, Csharp, Eflat ;.class Instrument public: vi

7、rtual void play(note) const cout Instrument:play endl; ;/ Wind objects are Instruments/ because they have the same interface:class Wind : public Instrument public: / Redefine interface function: void play(note) const cout Wind:play endl; ;void tune(Instrument& i) / . i.play(middleC);int main() Wind

8、flute; tune(flute); / Upcasting return 0; 将基类函数play函数定义成为虚函数virtual function初见虚函数虚函数(virtual function)的定义virtual 返回类型 函数名参数表;class Shapeprivate:public:virtual void Draw() cout “Draw a shapeendl; ;派生类中的虚函数虚函数是类成员函数(class member function);在派生类(derived class)中对虚函数的实现重新定义称之为覆盖(override)虚函数的“身份在继承之间能被持续传

9、递下去再次运行,结果#include using namespace std;enum note middleC, Csharp, Eflat ;.class Instrument public: virtual void play(note) const cout Instrument:play endl; ;/ Wind objects are Instruments/ because they have the same interface:class Wind : public Instrument public: / Redefine interface function: void

10、 play(note) const cout Wind:play endl; ;void tune(Instrument& i) / . i.play(middleC);int main() Wind flute; tune(flute); / Upcasting return 0; 这次结果是我们希望的结果!我们引入了虚函数机制,导致了这样的结果。“神奇的 执行方式 ?以基类指针运行虚函数,程序就能执行我们所期望的正确的派生类的函数体,虚函数为什么会有这样“神奇的运行机制呢?通过继承而相关的不同类,他们的对象能够对同一个函数作出不同的响应.这样“神奇的 多态性是怎样实现的呢?静态绑定与动态绑

11、定绑定(binding)程序自身彼此关联的过程,确定程序中的操作调用与执行该操作的代码间的关系。静态绑定(early binding)绑定过程出现在编译阶段,用对象名或者类名来限定要调用的函数。动态绑定(dynamic/later binding)绑定过程工作在程序运行时执行,在程序运行时才确定将要调用的函数。“神奇的 执行方式 动态绑定C+的虚函数在运行时正是通过动态绑定实现多态机制的。动态绑定是如何实现的呢?动态绑定是通过编译器运用虚函数表VTBL和虚表指针VPTR而实现,在运行时通过动态查询实现对正确函数体的绑定。VTBL编译器会为声明了虚函数的类建立一个虚函数表。VTBL实际上是一个函

12、数指针数组,每个虚函数占用这个数组的一个入口slot。一个类只有一个VTBL,不管它有多少个实例。派生类有自己的VTBL,但是派生类的VTBL与基类的VTBL有相同的函数排列顺序,同名的虚函数被放在两个数组的相同位置上。 VPTR在创立类实例的时候,编译器还会在每个实例的内存布局中增加一个VPTR指针,该指针指向本类的VTBL。 最后,是动态联编在调用此类的构造函数时,在类的构造函数中,编译器会隐含执行VPTR与VTBL的关联代码,将VPTR指向对应的VTBL。这就将类与此类的VTBL联系了起来。在调用类的构造函数时,指向基类的指针此时已经变成指向具体的类的this指针,依靠此this指针,进

13、一步得到正确的VPTR,即可得到正确的VTBL,从而实现了多态性。在此时才能真正与函数体进行连接,这就是动态联编。一个更大的例子#include using namespace std; enum note middleC, Csharp, Cflat ; / Etc. class Instrument public: virtual void play(note) const cout Instrument:play endl; virtual char* what() const return Instrument; virtual void adjust(int) ; class Win

14、d : public Instrument public: void play(note) const cout Wind:play endl; char* what() const return Wind; void adjust(int) ; class Percussion : public Instrument public: void play(note) const cout Percussion:play endl; char* what() const return Percussion; void adjust(int) ; class Stringed : public I

15、nstrument public: void play(note) const cout Stringed:play endl; char* what() const return Stringed; void adjust(int) ; 一个更大的例子class Brass : public Wind public: void play(note) const cout Brass:play endl; char* what() const return Brass; ; class Woodwind : public Wind public: void play(note) const c

16、out Woodwind:play endl; char* what() const return Woodwind; ; void tune(Instrument& i) i.play(middleC); void f(Instrument& i) i.adjust(1); / Upcasting during array initialization: Instrument* A = new Wind, new Percussion, new Stringed, new Brass, ; 一个更大的例子int main() Wind flute; Percussion drum; Stri

17、nged violin; Brass flugelhorn; Woodwind recorder; tune(flute); tune(drum); tune(violin); tune(flugelhorn); tune(recorder); f(flugelhorn); /: f(flugelhorn)函数调用的是哪个版本的adjust()函数呢?虚函数的特点实现动态多态性时,必须使用基类类型的指针pointer或引用(reference)型变量,通过该变量引用虚函数,才能实现动态的多态性。只有类的成员函数才能说明为虚函数。这是因为虚函数仅适用于有继承关系的类对象。静态static成员函数

18、,为所有同一类对象共有,不受限于某个对象,不能作为虚函数。虚函数的特点派生类中定义虚函数必须与基类中的虚函数同名外,还必须同参数表,同返回类型。否那么被认为是重载(overload),而不是虚函数。 如果定义放在类外,virtual只能加在函数声明前面,不能再加在函数定义前面。虚函数的特点析构函数可定义为虚函数,构造函数不能定义虚函数,因为在构造函数时对象还没有完成实例化。在基类中及其派生类中都动态分配的内存空间时,必须把析构函数定义为虚函数,实现撤消对象时的多态性。采用了虚函数函数执行速度要稍慢一些。为了实现多态性,每一个派生类中均要保存相应虚函数的入口地址表,函数的调用机制也是间接实现。所

19、以多态性总是要付出一定代价,但通用性是一个更高的目标。纯虚函数与抽象类纯虚函数(pure vitual function) 纯虚函数是指被标明为不具体实现的虚拟成员函数。它用于这样的情况:定义一个基类时,会遇到无法定义基类中虚函数的具体实现,其实现依赖于不同的派生类。 定义纯虚函数的一般格式为:virtual 返回类型 函数名参数表=0;定义纯虚函数须注意 定义纯虚函数时,不能定义虚函数的实现局部。即使是函数体为空也不可以,函数体为空就可以执行,只是什么也不做就返回。而纯虚函数不能调用。 在派生类中必须有重新定义的纯虚函数的函数体,这样的派生类才能用来定义对象。抽象类(abstract class)的定义 含有纯虚函数的基类是不能用来定义对象的。纯虚函数没有实现局部,不能产生对象,所以含有纯虚函数的类是抽象类。引入抽象类有何意义?1 基类的操作表达一种抽象的行为概念,而非能具体化的实体,不必也不能将基类对象实例化,因此使基类成为抽象类,让它表达一种表征共性的概念,而由派生类具体实现纯虚函数表达的概念。2 抽象类的纯虚函数表达了一种“规约和“协议的含义,只有接口的约定,没有实现的约束,这样就使接口与实现完成解耦,便于软件统一接口的同时保持实现的灵活性,这也正是组件编程的根本思想。抽象类的使用要求 抽象类不能实例化 抽象

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论