多态性给我们带来了好处:多态使得我们可以通过基类的引用或指针来指明一个对象(包含其派生类的对象),当调用函数时可以自动判断调用的是哪个对象的函数。
一个函数说明为虚函数,表明在继承的类中重载这个函数时,当调用这个函数时应当查看以确定调用哪个对象的这个函数。
普通函数的处理:一个特定的函数都会映射到特定的代码,无论时编译阶段还是连接阶段,编译器都能计算出这个函数的地址,调用即可。
虚函数的处理:被调用的函数不仅依据调用的特定函数,还依据调用的对象的种类。通常是由虚函数表(vtable)来实现的。
虚函数表的结构:它是一个函数指针表,每一个表项都指向一个函数。任何一个包含至少一个虚函数的类都会有这样一张表。需要注意的是vtable只包含虚函数的指针,没有函数体。实现上是一个函数指针的数组。虚函数表既有继承性又有多态性。每个派生类的vtable继承了它各个基类的vtable,如果基类vtable中包含某一项,则其派生类的vtable中也将包含同样的一项,但是两项的值可能不同。如果派生类重载(override)了该项对应的虚函数,则派生类vtable的该项指向重载后的虚函数,没有重载的话,则沿用基类的值。
每一个类只有唯一的一个vtable,不是每个对象都有一个vtable,恰恰是每个同一个类的对象都有一个指针,这个指针指向该类的vtable(当然,前提是这个类包含虚函数)。那么,每个对象只额外增加了一个指针的大小,一般说来是4字节。

在类对象的内存布局中,首先是该类的vtable指针,然后才是对象数据。

在通过对象指针调用一个虚函数时,编译器生成的代码将先获取对象类的vtable指针,然后调用vtable中对应的项。对于通过对象指针调用的情况,在编译期间无法确定指针指向的是基类对象还是派生类对象,或者是哪个派生类的对象(见代码中的函数f在编译期间是无法判断的)。但是在运行期间执行到调用语句时,这一点已经确定,编译后的调用代码能够根据具体对象获取正确的vtable,调用正确的虚函数,从而实现多态性。

给出实例代码:
class A {
public :
virtual void run (){......}
}
class B :public A{
public:
void run(){......}
}
int f (A *pA){
pA->run();
}
分析一下这里的思想所在,问题的实质是这样,对于发出虚函数调用的这个对象指针,在编译期间缺乏更多的信息,而在运行期间具备足够的信息,但那时已不再进行绑定了而是直接执行好了,怎么在二者之间作一个过渡呢?把绑定所需的信息用一种通用的数据结构记录下来,该数据结构可以同对象指针相联系,在编译时只需要使用这个数据结构进行抽象的绑定,而在运行期间将会得到真正的绑定。这个数据结构就是vtable,也就是编译期间建立vtable表,执行期间查表执行。可以看到,实现用户所需的抽象和多态需要进行后绑定,而编译器又是通过抽象和多态而实现后绑定的。
下面是通过基类的指针来调用虚函数时,所发生的一切:
step 1:开始执行调用 pA->run();(这里能判断到底是哪个对象)
step 2:取得对象的vtable的指针
step 3:从vtable那里获得函数入口的偏移量,即得到要调用的函数的指针
step 4:根据vtable的地址找到函数,并调用函数。
step 1和step 4对于一般函数是一样的,虚函数只是多了step 2和step 3。
解惑:
1基类和派生类是共用一表,还是各有各的表(物理上)
答:基类和派生类是各有各的表,也就是说他们的物理地址是分开的,基类和派生类的虚表的唯一关联是:当派生类没有实现基类虚函数的重载时,派生类会直接把自己表的该函数地址值写为基类的该函数地址值.
 

C++多态性:虚函数的调用原理的更多相关文章

  1. C++中虚函数的作用和虚函数的工作原理

    1 C++中虚函数的作用和多态 虚函数: 实现类的多态性 关键字:虚函数:虚函数的作用:多态性:多态公有继承:动态联编 C++中的虚函数的作用主要是实现了多态的机制.基类定义虚函数,子类可以重写该函数 ...

  2. 漫谈 C++ 虚函数 的 实现原理

    文中讲述的原理是推理和探讨 , 和现实中的实现不一定完全相同 . C++ 的 虚函数 , 编译器 会 生成一个 虚函数表 . 虚函数表, 实际上是 编译器 在 内存 中 划定 的 一块 区域, 用于存 ...

  3. C++虚函数的工作原理

    静态绑定与动态绑定 讨论静态绑定与动态绑定,首先需要理解的是绑定,何为绑定?函数调用与函数本身的关联,以及成员访问与变量内存地址间的关系,称为绑定. 理解了绑定后再理解静态与动态. 静态绑定:指在程序 ...

  4. MFC浅析(7) CWnd类虚函数的调用时机、缺省实现

    CWnd类虚函数的调用时机.缺省实现 FMD(http://www.fmdstudio.net) 1. Create 2. PreCreateWindow 3. PreSubclassWindow 4 ...

  5. C++ 之虚函数的实现原理

    c++的多态使用虚函数实现,通过“晚绑定”,使程序在运行的时候,根据对象的类型去执行对应的虚函数. C++ 之虚函数的实现原理 带有虚函数的类,编译器会为其额外分配一个虚函数表,里面记录的使虚函数的地 ...

  6. 多态性&& 虚函数 && 抽象类

    http://www.cnblogs.com/CaiNiaoZJ/archive/2011/08/11/2134673.html 多态性 指相同对象收到不同消息或不同对象收到相同消息时产生不同的实现动 ...

  7. Direct3D Draw函数 异步调用原理解析

    概述 在D3D10中,一个基本的渲染流程可分为以下步骤: 清理帧缓存: 执行若干次的绘制: 通过Device API创建所需Buffer: 通过Map/Unmap填充数据到Buffer中: 将Buff ...

  8. C++虚函数实现多态原理(转载)

    一.前言 C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数.这种技术可以让父类的指针有"多种形态 ...

  9. c++多态性---虚函数

    虚函数与纯虚函数的区别: 1.拥有虚函数的类可以声明对象,但拥有纯虚函数的类不可以声明对象(只能声明一个指针,并且不能给其分配内存),并且将这个类称为抽象类 特点: 1.虚函数是动态绑定的基础. 2. ...

随机推荐

  1. linux 块设备驱动(四)——简单的sbull实例

    #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> # ...

  2. align="absmiddle" 图片的中间上下对齐

    align=absmiddle表示图像的中间与同一行中最大元素的中间对齐 AbsBottom 图像的下边缘与同一行中最大元素的下边缘对齐.AbsMiddle 图像的中间与同一行中最大元素的中间对齐.B ...

  3. Oracle中,将毫秒数转换为timestamp类型的两种方法

    在许多场景中,开发人员习惯用1970-01-01 00:00:00.000以来的毫秒数来表示具体的时间,这样可以将数据以NUMBER类型存储到数据库中,在某些时候方便比较,同样,有些时候我们需要 把这 ...

  4. ACM-BFS之Open the Lock——hdu1195(双向BFS)

    这道题的0基础版本号,暴力BFS及题目详情请戳:http://blog.csdn.net/lttree/article/details/24658031 上回书说道,要用双向BFS来尝试一下. 最终A ...

  5. 设置netbeans文件编码格式

    在项目ecmall上右键 选择属性,然后在项目属性里设置

  6. Java类加载器( 死磕 6)

    [正文]Java类加载器(  CLassLoader )死磕 6:  自定义网络类加载器 本小节目录 6.1. 自定义网络类加载器的类设计 6.2. 文件传输Server端的源码 6.3. 文件传输C ...

  7. thinkphp3.2独立分组的建立

    很简单,就是把默认的Home模块复制一份,放到Admin目录下,同时把namespace改成namespace Admin\Controller即可,配置项如下:

  8. 青岛理工交流赛 H题 素数间隙

    13110581088注销 素数间隙 Time Limit: 1000MS Memory limit: 262144K 题目描述 Neko猫是一个很喜欢玩数字游戏的会说话的肥猫,经常会想到很多很好玩的 ...

  9. ios 使用json

    1.从https://github.com/stig/json-framework/中下载json框架:json-framework 2.解压下载的包,将class文件夹下的所有文件导入到当前工程下. ...

  10. html5--3.10 input元素(9)

    html5--3.10 input元素(9) 学习要点 input元素及其属性 input元素 用来设置表单中的内容项,比如输入内容的文本框,按钮等 不仅可以布置在表单中,也可以在表单之外的元素使用 ...