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使用方 ...
随机推荐
- eclipse 用links 安装插件
eclipse 用links 安装插件: 1.在eclipse目录下新建文件夹links 2.在links里新建文件 "控件名".link controlName.link 3.在 ...
- FPGA重要设计思想
FPGA重要设计思想 1.速度和面积互换原则.以面积换速度可以实现很高的数据吞吐率,其实串/并转换.就是一种以面积换速度的思想 2.乒乓操作. 3.串/并转换的思想. 高速数据处理的重要技巧之一. ...
- spring.net学习(一) 搭建环境,实例化spring.net容器。
1,使用nuget安装SPring.Core.安装这个的同时,会把Common.Logging,Common.Logging.Core也装上. 2,建立对象配置xml文件.如图Objects.xml. ...
- 关于mysql中实现replace的sql语句
update 表名 set 字段名=replace(字段名, '旧字符串', '新字符串')
- (转载)MongoingDB常用操作
mongo –path db.AddUser(username,password) 添加用户 db.auth(usrename,password) 设置数据库连接验证 db.cloneDat ...
- LEfSe分析
LEfSe软件用于发现两组或两组以上的biomarker,主要是通过非参数因子Kruskal-Wallis秩和检验来实现的.运行LEfSe软件主要分三大步骤:第一步:需要把普通的物种.基因等等的丰度信 ...
- js 对多sheet Excel赋值操作
function ExpExcel(){ var tempStr = ""; var filePath ="" var excelname=ReportFile ...
- 淘宝网触屏版 - 学习笔记(1 - 关于meta)
注:本文是学习笔记,并不是教程,所以会有很多我不理解或猜测的问题,也会有不尽详实之处,望见谅. <meta charset="utf-8"> <meta cont ...
- Sublime Text3 快捷键
选择类 Ctrl+D 选中光标所占的文本,继续操作则会选中下一个相同的文本. Alt+F3 选中文本按下快捷键,即可一次性选择全部的相同文本进行同时编辑.举个栗子:快速选中并更改所有相同的变量名.函数 ...
- iOS - MKMapView 地图
1.创建 MKMapView 地图 在 iOS6 或者 iOS7 中实现这个功能只需要添加地图控件.设置用户跟踪模式.在 mapView:didUpdateUserLocation: 代理方法中设置地 ...