前导

在上面的博文中描述了基类中存在虚函数时,基类和派生类中虚函数表的结构。

在派生类也定义了虚函数时,函数表又是怎样的结构呢?

先看下面的示例代码:

 #include <iostream>

 using namespace std;

 class A
{
public:
virtual void funcA(){ cout<<"A"<<endl; }
}; class B
{
public:
virtual void funcB(){ cout<<"B"<<endl; }
}; class C : public A, public B
{
public:
virtual void funcC(){ cout<<"C"<<endl; }
}; int main()
{
C c;
cin.get();
}

class A 和 class B 都有一个虚函数,然后 class C 继承 A 和 B。在VS2010中,查看变量:

如图所示,局部变量中只显示了从 A 和 B 继承来的虚函数表地址。那么 C 自己的虚函数呢?

首先查看 A 虚函数表地址:

可以看到,虚函数表中的前4个字节就是 A 中虚函数的地址(红色框)。同时后面又紧跟着4个有内容的字节,然后才是表示虚函数表结束的4个0。

可以猜测,这应该就是 C 的虚函数地址。再来看一下 B 的虚函数表:

可以看到,虚函数表中只有 B 的虚函数这一个地址。为了证实上面的猜测,将函数指针从 A::funcA 向后递增一次,应该就是对 C::funC的调用:

int main()
{
typedef void(*pfun)(); C c;
auto p = &c; auto funcA = (pfun)**((int**)p);
funcA(); // 调用 A::funcA auto funcC = (pfun)*(*((int**)p) + );
funcC(); // 调用 C::funcC cin.get();
}

输出结果: 证实了我们的猜测。

如果在增加一个 class D 继承 C 呢?

class D : public C
{
virtual void funcD() {}
}; int main()
{
D d; cin.get();
}

变量:

和 C 中展示的一样,只有两个虚函数表。

内存:

可以看到,在 A::funcA 后还有两个地址,可以推测就是 C::funcC 和 D::funcD 的地址了。

总结:

1、在多继承中,派生类的虚函数表的个数由它所继承的“顶层的”基类的个数决定:有多少个这样的基类,就有多少个虚函数表。

2、派生类自己的虚函数被追加到第一个虚函数表的后面。

例如下面的继承:

假设每个类 X 都有一个 funcX 虚函数,那么G中虚函数和虚函数表如下:

C++虚函数和虚函数表的更多相关文章

  1. C++虚函数及虚函数表解析

    一.背景知识(一些基本概念) 虚函数(Virtual Function):在基类中声明为 virtual 并在一个或多个派生类中被重新定义的成员函数.纯虚函数(Pure Virtual Functio ...

  2. C++ 由虚基类 虚继承 虚函数 到 虚函数表

    //虚基类:一个类可以在一个类族中既被用作虚基类,也被用作非虚基类. class Base1{ public: Base1(){cout<<"Construct Base1!&q ...

  3. 20140321 sizeof 虚函数与虚函数表 静态数组空间 动态数组空间 位字段

    1.静态的数组空间char a[10];sizeof 不能用于1:函数类型 2:动态的数组空间new3:位字段 函数类型:int fun();sizeof(fun())计算的是返回类型的大小,并不是函 ...

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

    静态多态.动态多态 静态多态:程序在编译阶段就可以确定调用哪个函数.这种情况叫做静态多态.比如重载,编译器根据传递给函数的参数和函数名决定具体要使用哪一个函数.动态多态:在运行期间才可以确定最终调用的 ...

  5. 为何JAVA虚函数(虚方法)会造成父类可以"访问"子类的假象?

      首先,来看一个简单的JAVA类,Base. 1 public class Base { 2 String str = "Base string"; 3 protected vo ...

  6. C++基础知识 基类指针、虚函数、多态性、纯虚函数、虚析构

    一.基类指针.派生类指针 父类指针可以new一个子类对象 二.虚函数 有没有一个解决方法,使我们只定义一个对象指针,就可以调用父类,以及各个子类的同名函数? 有解决方案,这个对象指针必须是一个父类类型 ...

  7. virtual之虚函数,虚继承

    当类中包含虚函数时,则该类每个对象中在内存分配中除去数据外还包含了一个虚函数表指针(vfptr),指向虚函数表(vftable),虚函数表中存放了该类包含的虚函数的地址. 当子类通过虚继承的方式从父类 ...

  8. C++纯虚函数、虚函数、实函数、抽象类,重载、重写、重定义

    首先,面向对象程序设计(object-oriented programming)的核心思想是数据抽象.继承.动态绑定.通过数据抽象,可以使类的接口与实现分离,使用继承,可以更容易地定义与其他类相似但不 ...

  9. 虚函数&纯虚函数&抽象类&虚继承

    C++ 虚函数&纯虚函数&抽象类&接口&虚基类   1. 多态 在面向对象语言中,接口的多种不同实现方式即为多态.多态是指,用父类的指针指向子类的实例(对象),然后通过 ...

随机推荐

  1. 远程连接redis

    1.在ubuntu上的redis作为服务端,默认是打开的 在redis的配置文件redis.conf中,找到bind localhost注释掉. 注释掉本机,局域网内的所有计算机都能访问. bind ...

  2. JS实现继承的几种方式

    前言 JS作为面向对象的弱类型语言,继承也是其非常强大的特性之一.那么如何在JS中实现继承呢?让我们拭目以待. JS继承的实现方式 既然要实现继承,那么首先我们得有一个父类,代码如下: // 定义一个 ...

  3. 【Java】集合_学习笔记

    一.集合 1.集合类也称容器类,主要负责保存.盛装其他数据. 2.集合可以保存数量不确定的数据,保存具有映射关系的数据(也称关联数组). 3.Java5后提供一些多线程安全的集合类,放在java.ut ...

  4. duilib的caption上的Edit无法激活

    当窗口设置标题栏时,鼠标等控件可以相应,edit无法响应. 主要和WindowImplBase::OnNcHitTest 虚函数有关. LRESULT WindowImplBase::OnNcHitT ...

  5. VMWARE里启动kylin16.0时出现'SMBus Host Controller not enabled'(还未进入系统)

    在Vmware里安装完Ubuntu16.10,启动时出现'SMBus Host Controller not enabled'错误提示,进不到图形界面.网上搜了一下,解决办法是在图形界面里进终端窗口, ...

  6. 安装idea开发工具

    1.网上去下载一个安装包,有的是需要注册码的(可以网上搜索注册码) 2.设置快捷键,可以直接选择使用eclipse的快捷键 3.配置maven 4.配置Git 5.配置tomcat

  7. linux笔记:shell编程-文本处理命令

    cut(字段提取命令,也叫列提取命令): printf(格式化输出命令): awk(awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理): sed(sed是一个很好 ...

  8. java中的成员变量和局部变量区别

    1.作用域不同 成员变量的作用域在整个类内部都是可见,可用的: 局部变量的作用域仅限于定义它的方法,不能被其它方法调用: 2.初始值不同 java会给成员变量一个初始值,初始值为0: java不会给局 ...

  9. document.all.wb.ExecWB

      <%@ page language="java" pageEncoding="UTF-8"%>   <%@ taglib uri=&quo ...

  10. mybatis高级(3)_延迟加载_深度延迟_一级缓存_二级缓存

    设置延迟加载需要在mybatis.xml中设置 注: 侵入式延迟加载为真时是延迟加载 侵入式延迟加载为假时是深度延迟加载 <!-- 延迟加载和深度延迟加载 --> <settings ...