C++迟后联编和虚函数表
先看一个题目:
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 = ;
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 ;
} 输出结果为:D A、In Base class, int x = ;
In Base class, int x = ;
In Derived, int x = ;
In Derived, float x = ;
B、In Base class, int x = ;
In Base class, int x = ;
In Derived, float x = ;
In Derived, float x = ;
C、In Base class, int x = ;
In Base class, int x = ;
In Base, int x = ;
In Base, float x = ;
D、In Base class, int x = ;
In Base class, int x = ;
In Base class, int x = ;
In Base class, int x = ;
理由:如果虚函数在基类与子类中出现的仅仅是名字的相同,而参数类型不同,或者返回类型不同,即使写上了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
C++迟后联编和虚函数表的更多相关文章
- 深入剖析C++多态、VPTR指针、虚函数表
在讲多态之前,我们先来说说关于多态的一个基石------类型兼容性原则. 一.背景知识 1.类型兼容性原则 类型兼容规则是指在需要基类对象的任何地方,都可以使用公有派生类的对象来替代.通过公有继承,派 ...
- C++多态,虚函数,虚函数表,纯虚函数
1.多态性 指相同对象收到不同消息或不同对象收到相同消息时产生不同的实现动作. C++支持两种多态性:编译时多态性,运行时多态性. a.编译时多态性:通过重载函数实现 ,模板(2次编译) ...
- c++ 虚函数多态、纯虚函数、虚函数表指针、虚基类表指针详解
静态多态.动态多态 静态多态:程序在编译阶段就可以确定调用哪个函数.这种情况叫做静态多态.比如重载,编译器根据传递给函数的参数和函数名决定具体要使用哪一个函数.动态多态:在运行期间才可以确定最终调用的 ...
- C++虚函数表与虚析构函数
1.静态联编和动态联编联编:将源代码中的函数调用解释为要执行函数代码. 静态联编:编译时能确定唯一函数.在C中,每个函数名都能确定唯一的函数代码.在C++中,因为有函数重载,编译器须根据函数名,参数才 ...
- C++ 虚函数表与多态 —— 虚函数表的内存布局
C++面试经常会被问的问题就是多态原理.如果对C++面向对象本质理解不是特别好,问到这里就会崩. 下面从基本到原理,详细说说多态的实现:虚函数 & 虚函数表. 1. 多态的本质: 形 ...
- C++ 多态、虚函数机制以及虚函数表
1.非virtual函数,调用规则取决于对象的显式类型.例如 A* a = new B(); a->display(); 调用的就是A类中定义的display().和对象本体是B无关系. 2. ...
- C++虚函数和虚函数表
前导 在上面的博文中描述了基类中存在虚函数时,基类和派生类中虚函数表的结构. 在派生类也定义了虚函数时,函数表又是怎样的结构呢? 先看下面的示例代码: #include <iostream> ...
- 对C++虚函数、虚函数表的简单理解
一.虚函数的作用 以一个通用的图形类来了解虚函数的定义,代码如下: #include "stdafx.h" #include <iostream> using name ...
- 深入理解C++虚函数表
虚函数表是C++类中存放虚函数的一张表,理解虚函数表对于理解多态很重要. 本次使用的编译器是VS2013,为了简化操作,不用去操作函数指针,我使用到了VS的CL编译选项来查看类的内存布局. CL使用方 ...
随机推荐
- jQuery禁用快捷键例如禁用F5刷新 禁用右键菜单等
禁用鼠标右键菜单栏 $("body").bind("contextmenu", function(event) { return false; }); 禁用快捷 ...
- ubuntu下安装JDK并搭建activeMQ
1.安装JDK,网上有人说activeMQ支持持JDK1.7及以上版本,未实际测试,保险起见我这里直接安装JDK1.7. #apt-get install openjdk--jdk 2.设置环境变量 ...
- 如何在Python中实现这五类强大的概率分布
R编程语言已经成为统计分析中的事实标准.但在这篇文章中,我将告诉你在Python中实现统计学概念会是如此容易.我要使用Python实现一些离散和连续的概率分布.虽然我不会讨论这些分布的数学细节,但我会 ...
- FireDAC 连接access MDB数据库的方法
Use Cases Open the Microsoft Access database. DriverID=MSAcc Database=c:\mydata.mdb Open the Microso ...
- 【POJ2886】Who Gets the Most Candies?-线段树+反素数
Time Limit: 5000MS Memory Limit: 131072K Case Time Limit: 2000MS Description N children are sitting ...
- 修改bootstrap modal模态框的宽度
原文链接:http://blog.csdn.net/wuhawang/article/details/52252912 修改模态框的宽度很简单,修改width属性就可以了 但是要注意的一点是,修改的不 ...
- 网易测试分享会——“一起打造你想要的QA团队”
昨天(2016.11.30)参加了网易资深测试专家王晓明的测试分享会——“一起打造你想要的QA团队”,以下为笔者做的归纳总结. 重点 1.让测试更加容易做好.不容易测试的代码,不具有健壮性. 2.Ke ...
- Android项目架构之业务组件化
前言: 从个人经历来说的话,从事APP开发这么多年来,所接触的APP的体积变得越来越大,业务的也变得越来越复杂,总来来说只有一句话:这是一个APP臃肿的时代!所以为了告别APP臃肿的时代,让我们进入一 ...
- 修改shell提示符的显示格式
默认的提示符显示方式如下: [root@localhost foldername]# 由于太长,希望能缩短到: [foldername]# 修改方式: # vim /etc/bashrc 找到第41行 ...
- CodeUI Test:创建第一个CodeUI Test
CodeUI Test是微软自动化测试的一个比较好的项目,它的原理是获取到Windows窗口上的控件,然后针对控件的部分属性进行获取和对比,模拟对控件进行点击.双击.右键点击等事件.这样可以录制用户测 ...