先看一个题目:

class Base
{
public:virtual void Show(int x){cout << "In Base class, int x = " << x << endl;}
};class Derived : public Base
{
public:virtual void Show(float x){cout << "In Derived, float x = " << x << endl;}
};void test (Base &b)
{int i = 1;b.Show(i);float f = 2.0;b.Show(f);
}int main(int argc, char *argv[])
{Base bc;Derived sc;test(bc);test(sc);return 0;
}输出结果为:DA、In Base class, int x = 1;In Base class, int x = 2;In Derived, int x = 1;In Derived, float x = 2;
B、In Base class, int x = 1;In Base class, int x = 2;In Derived, float x = 1;In Derived, float x = 2;
C、In Base class, int x = 1;In Base class, int x = 2;In Base, int x = 1;In Base, float x = 2;
D、In Base class, int x = 1;In Base class, int x = 2;In Base class, int x = 1;In Base class, int x = 2;

理由:如果虚函数在基类与子类中出现的仅仅是名字的相同,而参数类型不同,或者返回类型不同,即使写上了virtual关键字,也不进行迟后联编。

stackoverflow上,可以看到解释,http://stackoverflow.com/questions/27227189/override-virtual-function-with-different-parameters-in-c

C++里有两种编译类型:
1) 先期联编或静态联编:在编译时就能进行函数联编称为先期联编或静态联编。
2) 迟后联编或动态联编:在运行时才能进行的联编称为迟后联编或动态联编。

virtual关键字的作用就是提示编译器进行迟后联编,告诉链接过程:“我是个虚的,先不要连接我,等运行时再说”。 具体原理:当编译器遇到virtual后,会为所在的类构造一个表和一个指针,那个表叫做vtbl,每个类都有自己的vtbl,vtbl的作用就是保存自己类中虚函数的地址,我们可以把vtbl形象地看成一个数组,这个数组的每个元素存放的就是虚函数的地址,指针叫做vptr,指向那个表。而这个指针保存在相应的对象当中,也就是说只有创建了对象以后才能找到相应虚函数的地址。

对于下面这种常见代码(假如Base是Derive的父类):

Base *p=new Derive();
p->virtual_fun();

在程序运行时,根据对象的类型去初始化vptr,从而让vptr正确的指向所属类的虚表。上述程序中,由于p实际指向的对象类型是Derive,因此vptr指向的Derive类的vtable,当调用p->virtual_fun()时,根据虚表中的函数地址找到的就是Derive类的virtual_func()函数。

假设我们有这样的一个类:

class Base {public:virtual void f() { cout << "Base::f" << endl; }virtual void g() { cout << "Base::g" << endl; }virtual void h() { cout << "Base::h" << endl; }};

对应的虚函数表:

假设有如下所示的一个继承关系:

对于实例:Derive d; 的虚函数表如下:

如果是多继承:

对于实例:Derive d; 的虚函数表如下:

而C++标准规定:为确保运行时的多态定义的基类与派生类的虚函数不仅函数名要相同,其返回值及参数都必须相同,否则即使加上了virtual,系统也不进行迟后联编。

因此,对于最初的题目,Base的虚函数表里仅仅有一个Show方法,由于Derived子类重载了Show函数,那么Derived的虚函数表里实际上有两个Show方法,

因此,从Base角度去调用Show方法也只能是调用Base自己的方法了。

虚函数表的例子参考了:http://blog.csdn.net/haoel/article/details/1948051

转载于:https://www.cnblogs.com/bonelee/p/5824490.html

C++迟后联编和虚函数表相关推荐

  1. 【C++grammar】多态、联编、虚函数

    目录 1.多态概念 1.多态性有两种表现的方式 2.联编(实现多态) 1.静态联编 2.动态联编 3.实现运行时多态 1.为何要使用运行时多态? 2.如何实现运行时多态 3.多态的例子 1.调用哪个同 ...

  2. 深入剖析C++多态、VPTR指针、虚函数表

    在讲多态之前,我们先来说说关于多态的一个基石------类型兼容性原则. 一.背景知识 1.类型兼容性原则 类型兼容规则是指在需要基类对象的任何地方,都可以使用公有派生类的对象来替代.通过公有继承,派 ...

  3. c++ 虚函数多态、纯虚函数、虚函数表指针、虚基类表指针详解

    文章目录 静态多态.动态多态 虚函数 哪些函数类型不可以被定义成虚函数? 虚函数的访问方式 析构函数中的虚函数 虚函数表指针 vptr 多继承下的虚函数表 虚基类表指针 bptr 纯虚函数 抽象类 虚 ...

  4. C++ 面向对象(二)多态 : 虚函数、多态原理、抽象类、虚函数表、继承与虚函数表

    目录 多态 多态的概念 多态的构成条件 虚函数 虚函数的重写 协变(返回值不同) 析构函数的重写(函数名不同) final和override final override 重载, 重写, 重定义对比 ...

  5. C++之多态 虚函数表

    多态 多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为. 需要区分一下:1.菱形虚拟继承,是在继承方式前面加上virtual: class Person {}; class Studen ...

  6. C++中的虚函数表介绍

            在C++语言中,当我们使用基类的引用或指针调用一个虚成员函数时会执行动态绑定.因为我们直到运行时才能知道到底调用了哪个版本的虚函数,所以所有虚函数都必须有定义.通常情况下,如果我们不使 ...

  7. C/C++杂记:虚函数的实现的基本原理 虚函数表

    Malecrab 博客园 首页 新随笔 联系 订阅 管理 C/C++杂记:虚函数的实现的基本原理 1. 概述 简单地说,每一个含有虚函数(无论是其本身的,还是继承而来的)的类都至少有一个与之对应的虚函 ...

  8. C++虚函数表,虚表指针,内存分布

    虚函数表和内存分布那一块转载自:https://blog.twofei.com/496/ 虚函数效率转载自:https://www.cnblogs.com/rollenholt/articles/20 ...

  9. 【C++】 C++虚函数表详细分析(上)

    C++虚函数表详细分析 01. 目录 C++虚函数表详细分析 01. 目录 02. 虚函数表 03. 测试代码 04. 指针基础知识 05. _vptr 06. 结果分析 07. vptr. vtab ...

最新文章

  1. 记录在Spring-Boot中使用Fegin调用RESTfull的PATCH方法设置
  2. LNMP平台搭建之一:nginx编译安装
  3. CI框架 守护进程nohup让PHP以常驻内存的形式执行订阅消息
  4. [zz]grep 命令的使用
  5. Linux学习笔记之——Linux硬盘分区知识
  6. 2019年第十届蓝桥杯 - 省赛 - C/C++研究生组 - G. 扫地机器人
  7. CF 295A - Greg and Array 差分數列
  8. 马斯克和贝索斯的“星球大战”
  9. Win7系统浏览器的兼容模式如何设置
  10. IO流的应用_Copy文件
  11. 凸优化系列一:什么是最优化算法
  12. data image转换图片php,PHP 将dataurl转成图片image方法总结
  13. 利用Fiddler作为网络代理
  14. paypal如何支付欧元_Paypal怎么付欧元
  15. excel数据透视表之交叉表分组
  16. 【丢不掉的爱好-Android01】兜兜转转
  17. ThingWorx公开课圆满结束
  18. Unity 年度总结:一款游戏的从0到1
  19. HFSS和CST电磁仿真的硬件选型指南(纯个人经验)
  20. Android之CardView

热门文章

  1. 手机python代码阅读_教你阅读Python开源项目代码!
  2. 计算机网络数据分析报告,贵州大学计算机网络实验报告-实验四-分析IP协议数据包格式...
  3. html点击旋转180,关于点击三角丝滑旋转180度css3 jq处理方法
  4. cassandra hbase_为什么选择Cassandra
  5. php python插件安装,小弟我的vim配置和插件 小型 python php IDE
  6. mysql服务实例配置_MySQL多实例配置(一)
  7. Java后端简历模板,转疯了!
  8. java组长一个月工资多少,保准看明白!
  9. 升职加薪必看!如何试出一个Java开发者真正的水平
  10. Keras【Deep Learning With Python】MNIST数据集识别优化