在上一篇文章中讨论了C++单一一般继承的对象内存布局http://www.cnblogs.com/uangyy/p/4621561.html

接下来继续讨论第二种情况:

2.单一的虚拟继承:有成员变量,有虚函数和虚函数的覆盖,虚拟继承。

我们假设下面这样一种继承关系

源码如下:

#include <iostream>
using namespace std; class Parent
{
public:
int iparent;
Parent() : iparent() {}
virtual void f()
{
cout << "Parent::f()" << endl;
}
virtual void g()
{
cout << "Parent::g()" << endl;
}
}; class Child : virtual public Parent
{
public:
int ichild;
Child() : ichild() {}
virtual void f()
{
cout << "Child::f()" << endl;
}
virtual void g_child()
{
cout << "Child::g_child()" << endl;
}
};
int main(int argc, char **argv)
{
Child c;
typedef void(*Fun)(void);
Fun pf; cout << "[0] Child::vfptr->" << endl;
cout << " [0] ";
pf = (Fun)*((int *)*(int *)&c + );
pf(); cout << " [0] 0x" << (Fun)*((int *)*(int *)&c + ) << endl; cout << "[1] Child::vbptr->" << endl;
cout << " [0] " << *((int *)*((int *)&c + ) + ) << endl; cout << " [1] " << *((int *)*((int *)&c + ) + ) << endl; cout << " [2] " << *((int *)*((int *)&c + ) + ) << endl; cout << "[2] Child.ichild = " << (int)*((int *)&c + ) << endl; cout << "[3] = 0x" << (int *)*((int *)&c + ) << endl; cout << "[4] Parent::vfptr->" << endl;
cout << " [0] ";
pf = (Fun)*((int *)*((int *)&c + ) + );
pf(); cout << " [1] ";
pf = (Fun)*((int *)*((int *)&c + ) + );
pf(); cout << " [2] 0x" << (Fun)*((int *)*((int *)&c +) + ) << endl; cout << "[5] Parent.iparent = " << (int)*((int *)&c + ) << endl;
return ;
}

代码运行结果如下:

[] Child::vfptr->
[] Child::g_child()
[] 0x00000000
[] Child::vbptr->
[] -
[]
[]
[] Child.ichild =
[] = 0x00000000
[] Parent::vfptr->
[] Child::f()
[] Parent::g()
[] 0x00000000
[] Parent.iparent =

下面是该对象的内存布局图:

由上图我们可以知道:

  1.在虚拟继承关系下,派生类的对象会产生一个名为虚基类表指针的指针vbptr,里面存放的是基类在对象中的偏移地址(从1开始,0单元存放的不知道有什么用)

  2.在这种关系先,被继承的基类放在最后面,首先放的是派生类的成员变量和虚函数表

  3.存放的顺序为:派生类虚函数表指针 -> 虚基类表指针 -> 派生类的成员变量 -> NULL -> 基类虚函数表指针 -> 基类成员变量

sizeof(c) = 24 : 2 * sizeof(vfptr) + 2 * sizeof(int) + sizeof(vbptr) + sizeof(void *)

注意:1.在虚拟机城的继承关系下,派生类的对象会有一个虚基类表指针,占用4个字节;

2.在派生类和被虚拟继承的基类之间有一个空指针。

C++对象内存布局 (二)的更多相关文章

  1. 浅析GCC下C++多重继承 & 虚拟继承的对象内存布局

    继承是C++作为OOD程序设计语言的三大特征(封装,继承,多态)之一,单一非多态继承是比较好理解的,本文主要讲解GCC环境下的多重继承和虚拟继承的对象内存布局. 一.多重继承 先看几个类的定义: 01 ...

  2. JVM-对象及对象内存布局

    目录 前言 类与对象 对象类二分模型 对象 对象内存布局 JOL工具 对象头 Mark Word 类型句柄 对象头与锁膨胀 无锁 偏向锁 轻量级锁 重量级锁 重量级锁降级 实例数据 填充 对象生命周期 ...

  3. JVM 系列(4)一看就懂的对象内存布局

    请点赞关注,你的支持对我意义重大. Hi,我是小彭.本文已收录到 GitHub · AndroidFamily 中.这里有 Android 进阶成长知识体系,有志同道合的朋友,关注公众号 [彭旭锐] ...

  4. 图说C++对象模型:对象内存布局详解

    0.前言 文章较长,而且内容相对来说比较枯燥,希望对C++对象的内存布局.虚表指针.虚基类指针等有深入了解的朋友可以慢慢看. 本文的结论都在VS2013上得到验证.不同的编译器在内存布局的细节上可能有 ...

  5. c++ 对象内存布局详解

    今天看了的,感觉需要了解对象内存的问题.参考:http://blog.jobbole.com/101583/ 1.何为C++对象模型? 引用<深度探索C++对象模型>这本书中的话: 有两个 ...

  6. c++对象内存布局

    这篇文章我要简单地讲解下c++对象的内存布局,虽然已经有很多很好的文章,不过通过实现发现有些地方不同的编译器还是会有差别的,希望和大家交流. 在没有用到虚函数的时候,C++的对象内存布局和c语言的st ...

  7. c++对象内存布局的理解

    我对c++对象内存布局的理解   引言 结合网上的一些资料,通过自己的一番摸索,得出了一点个人见解.现在写下来,希望与各位同学共同探讨,共同进步. 以下所有代码均是在VS2012下测试. 一个普通的基 ...

  8. 好文章系列C/C++——图说C++对象模型:对象内存布局详解

    注:收藏好文章,得出自己的笔记,以查漏补缺!     ------>原文链接:http://blog.jobbole.com/101583/ 前言 本文可加深对C++对象的内存布局.虚表指针.虚 ...

  9. 使用sos查看.NET对象内存布局

    前面我们图解了.NET里各种对象的内存布局,我们再来从调试器和clr源码的角度来看一下对象的内存布局.我写了一个测试程序来加深对.net对象内存布局的了解: using System; using S ...

随机推荐

  1. String字符串的完美度

    题目详情: 我们要给每个字母配一个1-26之间的整数,具体怎么分配由你决定,但不同字母的完美度不同, 而一个字符串的完美度等于它里面所有字母的完美度之和,且不在乎字母大小写,也就是说字母F和f的完美度 ...

  2. hibernate.cfg.xml配置

    hibernate.hbm2ddl.auto 配置: create:每次加载hibernate时都会删除上一次的生成的表,然后根据你的model类再重新来生成新表,哪怕两次没有任何改变也要这样执行,这 ...

  3. [ ZJOI 2006 ] Trouble

    \(\\\) \(Description\) 有\(N\)个人的环,每个人需要至少\(x_i\)种不同的物品,并且要求任意相邻的两人都没有相同的物品,求最少需要多少种物品. \(N\in [0,2\t ...

  4. Ajax——异步基础知识(三)

    封装异步请求 1.将函数作为参数进行使用 2.因为获取数据是在一个注册事件中获取的,所以只有事件触发的时候才会调用此函数 <!DOCTYPE html> <html lang=&qu ...

  5. html5——伸缩比例

    基本概念 1.父盒子设置了伸缩属性,子盒子设置伸缩比例 2.以上设置完之后子盒子会按照比例分布在父盒子中 3.当设置伸缩比例时默认会按照x轴方向分配,因为默认情况下伸缩布局主轴方向是x轴方向 4.设置 ...

  6. JS——三元表达式

    三元表达式: var n1 = 2 > 3 ? true : false; alert(n1);//返回false

  7. Resetting the SMC & PRAM

    Resetting the SMC & PRAM on portables with a battery you should not remove on your own 1. Shut d ...

  8. Navicat 连接docker mysql报错

    解决办法: docker exec -it dc10e8b328d7 bashmysql -u root -p 输入密码 use mysql; ALTER USER 'root'@'%' IDENTI ...

  9. uva-679 Dropping Balls UVA - 679

    题目大意 总共有一个深度为D的满二叉树,I个小球,每个节点具有开关,小球经过节点后节点开关会有变化,初始都关闭,若关闭往左右否则往右走 只需要循环一下每层的情况即可 代码 #include <b ...

  10. Linux常用shell命令持续总结

    1. 查看端口运行 netstat -lnp|grep 80 2. 定时任务 Crontab -e 编辑任务 Crontab -l 查看当前任务列表 /var/log/cron-* 任务日志