可以参考以下文章:

http://blog.csdn.net/haoel/archive/2007/12/18/1948051.aspx  陈皓 C++ 虚函数表解析

http://blog.csdn.net/haoel/archive/2008/10/15/3081328.aspx  陈皓 C++ 对象的内存布局(上)

http://blog.csdn.net/haoel/archive/2008/10/15/3081385.aspx  陈皓 C++ 对象的内存布局(下)

http://www.cnblogs.com/cswuyg/archive/2010/08/20/1804113.html  C++对象内存布局测试总结

这些文章的陈述和之前自己的理解还是比较吻合的。

但有一些细节需要注意一下,写在下面加深一下记忆。

(1)单一的一般继承 (带成员变量、虚函数、虚函数覆盖)

1)虚函数表在最前面的位置。

2)成员变量根据其继承和声明顺序依次放在后面。

3)在单一的继承中,被 overwrite 的虚函数在虚函数表中得到了更新 。

(2)多重继承 (带成员变量、虚函数、虚函数覆盖)

1)   每个父类都有自己的虚表。

2)   子类的成员函数被放到了第一个父类的表中。

3)   内存布局中,其父类布局依次按声明顺序排列。

4)   每个父类的虚表中的 f()函数都被 overwrite成了子类的 f() 。这样做就是为了解决不同的父类类型的指针指向同一个子类实例,而能够调用到实际的函数。

(3)重复多重继承 (带成员变量、虚函数、虚函数覆盖)

这个和上面一样,只不过最顶层的基类在二级子类里有两份同样的拷贝,在直接访问顶层基类的 成员变量时,会出现二义性。

d.ib = 0;             //二义性错误

d.B1::ib = 1;           //正确

d.B2::ib = 2;           //正确

(4)单一的虚拟继承 (带成员变量、虚函数、虚函数覆盖)

(5)钻石型的虚拟多重继承 (带成员变量、虚函数、虚函数覆盖)

第4和第5种情况就比较复杂了,因为这个内存布局其实是和具体的编译器相关的,不同的编译器实现不一样。

我们可以参照教材《inside c++ object model》P121和P123中的介绍。分别是使用pointer strategy和virtual table offset strategy.

在单一虚拟继承时:

(1)VS编译器:无论有无虚函数,必然含有虚基类表指针。虚基类表中的内容为本类实例的偏移和基类实例的相对偏移值。如果有虚函数,那么基类的虚函数表跟派生类的虚函数表是分开的。

(2)GNU的GCC编译器:跟VS的编译器类似,有不同的地方是,虚基类表跟派生类的虚函数表合并。另外通过虚基类表指针往正负两个方向寻址,可以获得不同偏移值,也就是说有两个功能一样的虚函数表 。

最后总结一下虚基类表的问题:

         VS编译器会去使用虚基类表,用于寻址虚基类地址(virtual base class table strategy )。而GCC编译器则没有这么做,而是直接在派生类对象地址上加上一个常数,获得虚基类实例的地址(virtual table offset strategy .)。

有一个很好的例子:

#include <stdio.h>

class A
{
public:
    virtual int foo0(){
        return 0;
    }
    char a[3];
};

class B: virtual public  A
{
public:
    virtual int foo1(){
        return 1;
    }
    char b[3];
};

class C:virtual public  B
{
public:
    virtual int foo2(){
        return 2;
    }
    char c[3];
};

int main(int argc, char* argv[])
{
    A a;
    B b;
    C c;

printf(" sizeof A=%d, sizeof B=%d, sizeof C=%d /n",sizeof (A), sizeof (B), sizeof (C));
    return 0;
}

在g++编译器里: sizeof A=8, sizeof B=16(A和B都有虚函数表,但B的虚函数表的负方面的地址里存着virtual base class(A)offset), sizeof C=24(C的虚函数表的负方面的地址里存着virtual base class(B)offset)

在VC++编译器里: sizeof A=8, sizeof B=20(A和B都有虚函数表,并且B还有一个virtual class base table pointer), sizeof C=32

继承----有关虚函数和虚拟继承相关推荐

  1. C++中的继承与虚函数各种概念

    虚继承与一般继承 虚继承和一般的继承不同,一般的继承,在目前大多数的C++编译器实现的对象模型中,派生类对象会直接包含基类对象的字段.而虚继承的情况,派生类对象不会直接包含基类对象的字段,而是通过一个 ...

  2. C++虚继承与虚函数

    虚继承和虚函数是完全无相关的两个概念. 虚继承是解决C++多重继承问题的一种手段,从不同途径继承来的同一基类,会在子类中存在多份拷贝.这将存在两个问题:其一,浪费存储空间:第二,存在二义性问题,通常可 ...

  3. C++ 在继承中虚函数、纯虚函数、普通函数,三者的区别

    C++ 在继承中虚函数.纯虚函数.普通函数,三者的区别 1.虚函数(impure virtual) C++的虚函数主要作用是"运行时多态",父类中提供虚函数的实现,为子类提供默认的 ...

  4. Visual C++ 2008入门经典 第九章类的继承和虚函数

    // 第九章类的继承和虚函数 //.cpp: 主项目文件. //1 继承如何与面向对像的编程思想适应 //2 根据现有类定义新类 //3 使用protected关键字为类成员指定新的访问特性 //4 ...

  5. c++虚继承和虚函数和抽象类、接口类,聚合类

    虚继承 虚继承用于解决多继承条件下的菱形继承问题(浪费存储空间.存在二义性). 底层实现原理与编译器相关,一般通过虚基类指针和虚基类表实现,每个虚继承的子类都有一个虚基类指针(占用一个指针的存储空间, ...

  6. C++编程思想:继承与虚函数以及多态

    文章目录 简介 实现虚函数多态的技术原理 对象切边 析构函数和构造函数中的虚函数 使用继承的类的析构函数应该使用虚函数修饰符 简介 继承与虚函数与多态是浑然一体的三个概念,父类中虚函数可以表现出多态特 ...

  7. C++之菱形继承与虚继承(含虚函数)

    面向对象的三大特征:封装,多态,继承 前面我们已经讲了继承的一些知识点,在这基础上,我们讲的时候再涉猎一些多态的只是. 下面我们先接着上次讲有虚函数的菱形虚继承 首先什么是虚函数.? 虚函数:在类里面 ...

  8. C++类内存分布——深度理解继承与虚函数

    1.前言与准备 工欲善其事,必先利其器,我们先用好Visual Studio工具,像下面这样一步一步来:       先选择左侧的C/C++->命令行,然后在其他选项这里写上/d1 report ...

  9. 类5-类的继承、虚函数、纯虚函数、虚析构函数

    一.类的继承 就像家谱一样,就是一个继承图.爷爷-父亲-儿子-孙子等.类也一样,上面的类称为基类,也称父类.基类下面的类叫子类也叫派生类. 子类对父类的一些属性等有所继承也有所发展,因此才有了类的继承 ...

最新文章

  1. 人工智能产业展望:2018年三大难题如何破解?
  2. JSON数据解析:Gson(谷歌)和fastjson(阿里巴巴)的异同点
  3. 树莓派进阶之路 (014) - 树莓派远程连接的三种方式总结
  4. 微软发文庆祝 .NET 诞生 20 周年纪念日!
  5. php授权验证系统源码-全解开源版
  6. 抓人眼球!插画风精美的网站首页设计欣赏
  7. C# 3.0新语言特性和改进(一)
  8. pythonsocket自动化教程_Python基本socket通信控制操作示例
  9. 【java学习之路】(java SE篇)009.IO
  10. 3814.矩阵变换-AcWing题库
  11. Python-Bunch模式
  12. 大国的崛起:第二集:小国大业 荷兰
  13. ArcGis空间分析学习:超市选址分析
  14. win7查看隐藏文件夹
  15. Python 实现图像快速傅里叶变换和离散余弦变换
  16. 关于理性形象的塑造——歇洛克·福尔摩斯眼中的世界
  17. 第三种是经典著作阅读法
  18. 2017 计蒜之道 初赛 第一场 A题(阿里的新游戏)
  19. 必读!ILRuntime来实现热更新的优与劣!
  20. JS如何替换元素内容

热门文章

  1. 11-27 概率论两种收敛方式
  2. 总后台顶部实现站内信功能
  3. birthday中文是什么_birthday是什么意思_birthday在线翻译_英语_读音_用法_例句_海词词典...
  4. MySQL 6:MySQL存储过程、存储函数
  5. 熵、图像熵的意义及计算方法
  6. 基于SSM的毕业设计管理系统
  7. android 通过电话号码来获取联系人姓名
  8. Ubcoin市场:加密货币-商品交易平台
  9. 【FlaskMySQL】Flask连接数据库MySQL(十)
  10. c语言测试软件的编写,用c语言编写智商测试软件