`
gaofen100
  • 浏览: 1187978 次
文章分类
社区版块
存档分类
最新评论

详细介绍C++中的虚函数和动态联编

 
阅读更多

 面向对象程序设计的基本观点是用程式来仿真大千世界,这使得它的各种根本特性非常人性化,如封装、继承、多态等等,而虚函数就是c++中实现多态性的主将。为了实现多态性,c++编译器也革命性地提供了动态联编(或叫晚捆绑)这一特征。

  虚拟函数亦是mfc编程的关键所在,mfc编程主要有两种方法:一是响应各种消息,进行对应的消息处理。二就是重载并改写虚拟函数,来实现自己的某些要求或改变系统的某些默认处理。

  虚函数的地位是如此的重要,对它进行穷根究底,力求能知其然并知其所以然 对我们编程能力的提高大有好处。下面且听我道来。

  多态性和动态联编的实现过程分析

  一、基础略(限于篇幅,请参阅相应的c++书籍):

  1、多态性:使用基础类的指针动态调用其派生类中函数的特性。

  2、动态联编:在运行阶段,才将函数的调用与对应的函数体进行连接的方式,又叫运行时联编或晚捆绑。

  二、过程描述:

  1、编译器发现一个类中有虚函数,编译器会立即为此类生成虚拟函数表 vtable(后面有对vtable的分析)。虚拟函数表的各表项为指向对应虚拟函数的指针。

  2、编译器在此类中隐含插入一个指针vptr(对vc编译器来说,它插在类的第一个位置上)。

  有一个办法可以让你感知这个隐含指针的存在,虽然你不能在类中直接看到它,但你可以比较一下含有虚拟函数时的类的尺寸和没有虚拟函数时的类的尺寸,你能够发现,这个指针确实存在。

  3、在调用此类的构造函数时,在类的构造函数中,编译器会隐含执行vptr与vtable的关联代码,将vptr指向对应的vtable。这就将类与此类的vtable联系了起来。

  4、在调用类的构造函数时,指向基础类的指针此时已经变成指向具体的类的this指针,这样依靠此this指针即可得到正确的vtable,从而实现了多态性。在此时才能真正与函数体进行连接,这就是动态联编。

  三、vtable 分析:

  分析1:虚拟函数表包含此类及其父类的所有虚拟函数的地址。如果它没有重载父类的虚拟函数,vtable中对应表项指向其父类的此函数。反之,指向重载后的此函数。

  分析2:虚拟函数被继承后仍旧是虚拟函数,虚拟函数非常严格地按出现的顺序在 vtable 中排序,所以确定的虚拟函数对应 vtable 中一个固定的位置n,n是一个在编译时就确定的常量。所以,使用vptr加上对应的n,就可得到对应函数的入口地址。

  四、编译器调用虚拟函数的汇编码(参考think in c++):

  push funparam ;先将函数参数压栈

  push si ;将this指针压栈,以确保在当前类上操作

  mov bx,word ptr[si] ;因为vc++编译器将vptr放在类的第一个位置上,所以bx内为vptr

  call word ptr[bx+n] ;调用虚拟函数。n = 所调用的虚拟函数在对应 vtable 中的位置

  纯虚函数:

  一、引入原因:

  1、为了方便使用多态特性,我们常常需要在基类中定义虚拟函数。

  2、在很多情况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。

  为了解决上述问题,引入了纯虚函数的概念,将函数定义为纯虚函数(方法:virtual returntype function()= 0;),则编译器要求在派生类中必须予以重载以实现多态性。同时含有纯虚拟函数的类称为抽象类,它不能生成对象。这样就很好地解决了上述两个问题。

  二、纯虚函数实质:

  1、类中含有纯虚函数则它的vtable表不完全,有一个空位,所以,不能生成对象(编译器绝对不允许有调用一个不存在函数的可能)。在它的派生类中,除非重载这个函数,否则,此派生类的vtable表亦不完整,亦不能生成对象,即它也成为一个纯虚基类。

  虚函数与构造、析构函数:

  1、构造函数本身不能是虚拟函数;并且虚机制在构造函数中不起作用(在构造函数中的虚拟函数只会调用它的本地版本)。

  想一想,在基类构造函数中使用虚机制,则可能会调用到子类,此时子类尚未生成,有何后果!?。

  2、析构函数本身常常要求是虚拟函数;但虚机制在析构函数中不起作用。

  若类中使用了虚拟函数,析构函数一定要是虚拟函数,比如使用虚拟机制调用delete,没有虚拟的析构函数,怎能保证delete的是你希望delete的对象。

  虚机制也不能在析构函数中生效,因为可能会引起调用已经被delete掉的类的虚拟函数的问题。

  对象切片:

  向上映射(子类被映射到父类)的时候,会发生子类的vtable 完全变成父类的vtable的情况。这就是对象切片。

  原因:向上映射的时候,接口会变窄,而编译器绝对不允许有调用一个不存在函数的可能,所以,子类中新派生的虚拟函数的入口在vtable中会被强行“切”掉,从而出现上述情况。

  虚拟函数使用的缺点

  优点讲了一大堆,现在谈一下缺点,虚函数最主要的缺点是执行效率较低,看一看虚拟函数引发的多态性的实现过程,你就能体会到其中的原因。

  希望通过以上内容的介绍,能够给你带来帮助。


原文出自【比特网】,转载请保留原文链接:http://soft.chinabyte.com/database/423/12134923.shtml

分享到:
评论

相关推荐

    虚函数和动态联编

    虚函数和动态联编的PP他,觉得有用的可以下载,勿拍砖

    C++虚函数与静态动态联编个人理解

    C++虚函数与静态动态联编个人理解

    C++实验六 多态性和虚函数的应用 课程 实验报告

    C++实验六 多态性和虚函数的应用 课程 实验报告 作业参考的良品!

    C++的静态联编和动态联编

    本文阐述了静态联编和动态联编的概念和区别,通过具体实例分析了实现动态联编的条件,指出了虚函数是实现动态联编的基础。

    C++多态性与虚函数

    第9章 多态性与虚函数 本章学习要求: 虚函数 多态性 静态与动态联编 9.1 多态性的概念 9.2 虚函数 9.3 静态绑定与动态绑定 9.4 纯虚函数和抽象类

    浅析C++中的虚函数

    一、定义定义:在某基类中声明为...二、作用虚函数的作用是实现动态联编,也就是在程序的运行阶段动态地选择合适的成员函数,在定义了虚函数后,可以在基类的派生类中对虚函数重新定义,在派生类中重新定义的函数应与虚

    C++的静态联编和动态联编详解

    静态联编是指在编译阶段就将函数实现和函数调用关联起来,因此静态联编也叫早绑定,在编译阶段就必须了解所有的函数或模块执行所需要检测的信息,它对函数的选择是基于指向对象的指针(或者引用)的类型,C语言中,...

    C语言和C++的重要知识点提炼.rar

    1.c++虚函数原理 作用:C++中的虚函数的作用主要是实现了多态的机制。当基类中的成员函数定义了虚函数,其子类可以重新改写该函数。也即是允许派生类调用父类的同名函数而实现不同的功能,也叫动态联编。在主函数...

    面向对象程序设计C++上机实验报告

    7.虚函数虚函数,实现虚函数支持的动态联编;功能:为一等学生发放奖金。,实现虚函数支持的动态联编;功能:为一等学生发放奖金。,实现虚函数支持的动态联编;功能:为一等学生发放奖金。,实现虚函数支持的动态联...

    虚函数与纯虚函数(C++与Java虚函数的区别)的深入分析

    虚函数的作用是实现动态联编,也就是在程序的运行阶段动态地选择合适的成员函数,在定义了虚函数后,可以在基类的派生类中对虚函数重新定义,在派生类中重新定义的函数应与虚函数具有相同的形参个数和形参类型(也...

    C++实验3:多态性与虚函数

    熟练掌握静态联编和动态联编的概念和用法 掌握纯虚函数和抽象类的概念和用法 实验内容 声明一个抽象类Shape,由它派生出3个类:Circle(圆),Rectangle(矩形)、Triangle(三角形),用函数分别输出以上三个图形的周长和...

    详解C++纯虚函数与抽象类

    为什么说虚函数是C++最重要的特性之一呢,因为虚函数承载着C++中动态联编的作用,也即多态,可以让程序在运行时选择合适的成员函数。虚函数必须是类的非静态成员函数(且非构造函数),其访问权限是public。那么: ...

    《c++面向对象程序设计》8-12章课后答案

    在C++语言中运行时的多态是通过继承和虚函数实现的。 8_4 什么是静态联编?什么是动态联编? 一个源程序需要经过编译、连接,才能成为可执行代码。 上述过程中需要将一个函数调用链接上相应的函数代码,这一过程称为...

    深入浅析C++多态性与虚函数

    面向对象的程序设计真正的力量不仅仅是继承,而且还在于允许派生类对象像基类对象一样处理,其核心机制就是多态和动态联编。 (一)多态性  多态是指同样的消息被不同的对象接收时导致不同的行为。所谓消息是指对类...

    C++ 编程思想(中文完整版)

    第1章 对象的演化 第2章 数据抽象 ...第14章 多态和虚函数 第15章 模板和包容器类 第16章 多 重 继 承 第17章 异 常 处 理 第18章 运行时类型识别 附录A 其 他 性 能 附录B 编 程 准 则 附录C 模拟虚构造函数

    零起点学通C++多媒体范例教学代码

    13.9.1 在虚函数中调用成员函数 13.9.2 3种调用虚函数的方式比较 13.10被继承的虚函数仍然是虚函数 13.11系统是如何调用虚函数的 13.12在虚函数中使用成员名限定 13.13虚析构函数 13.14总结 第14章 数组 14.1 数组...

    零起点学通C++学习_多媒体范例教学代码

    13.9.1 在虚函数中调用成员函数 13.9.2 3种调用虚函数的方式比较 13.10被继承的虚函数仍然是虚函数 13.11系统是如何调用虚函数的 13.12在虚函数中使用成员名限定 13.13虚析构函数 13.14总结 第14章 数组 ...

    C++面向对象程序设计-多态

    继承呼唤多态、虚函数、纯虚函数与抽象类、静态联编、动态联编

    C++面向对象课程序设计课件

    运行时多态性:动态联编支持的多态性(动态多态性)——通过虚函数实现。 四、函数重载 同一个类中的同名函数——参数个数不一样、参数类型不一样、参数个数及类型不一样; 不同类中的同名函数——通过类名调用或类...

    清华大学计算机课程之《C++程序设计》

    - 第二节 虚函数与动态联编 - 第三节 抽象类 - 第四节 虚析构函数 - 第五节 设计继承 - 第六节 程序举例 - 本章小结 - 课后习题 ◇ 第十二章 输入输出流 - 课前索引 - 第一节 输入输出流类 - 第二节 ...

Global site tag (gtag.js) - Google Analytics