C++对象的内存布局以及虚函数表和虚基表

本文为整理文章,

参考:

http://blog.csdn.net/haoel/article/details/3081328

http://blog.csdn.net/angelxf/article/details/7746034

整理的也不到位,还有很多不理解,先记下来。

遇到了一个面试题,是求对象所占空间的大小了。于是想了解一下C++中对象内存的布局。

先来一些结论,以便应付面试:

空类、单一继承的空类、多重继承的空类所占空间大小为:1(字节,下同);

一个类中,虚函数本身、成员函数(包括静态与非静态)和静态数据成员都是不占用类对象的存储空间的;

因此一个对象的大小≥所有非静态成员大小的总和;

当类中声明了虚函数(不管是1个还是多个),那么在实例化对象时,编译器会自动在对象里安插一个指针vPtr指向虚函数表VTable;

虚承继的情况:由于涉及到虚函数表和虚基表,会同时增加一个(多重虚继承下对应多个)vfPtr指针指向虚函数表vfTable和一个vbPtr指针指向虚基表vbTable,这两者所占的空间大小为:8(或8乘以多继承时父类的个数);

在考虑以上内容所占空间的大小时,还要注意编译器下的“补齐”padding的影响,即编译器会插入多余的字节补齐;

类对象的大小=各非静态数据成员(包括父类的非静态数据成员但都不包括所有的成员函数)的总和+ vfptr指针(多继承下可能不止一个)+vbptr指针(多继承下可能不止一个)+编译器额外增加的字节。

接下来说说虚函数表和虚基表

C++多态的实现和Java类似,都是利用虚函数表(Java叫方法表),不同的是,Java中,不用virtual修饰,函数自带virtual属性(指的是那些非静态函数)。之前的文章《从JVM角度看Java多态》中,也简单分析了Java多态的实现机制。C++和Java是类似的。下面我们直接分析吧。

对于单继承

Child类重写了Parent的f(),GrandChild类重写了Child类的f()和g_child();

GrandChild对象的内存布局为:

可以看到:

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

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

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

对于多继承

Derive对象的内存布局

可以看到:

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

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

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

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

对于菱形继承问题

D对象的内存布局

可以看到

我们可以看见,最顶端的父类B其成员变量存在于B1和B2中,并被D给继承下去了。而在D中,其有B1和B2的实例,于是B的成员在D的实例中存在两份,一份是B1继承而来的,另一份是B2继承而来的。所以,容易产生二义性。

对于虚继承

对于这种问题,VS中和G++采用不同的方式

在VS中 D的内存布局是这样的:


还不是很明白,总之就是公共基类B会放到最后,而且VS中会有虚基表的概念,vbptr就是指向虚基表的指针

对于g++则没有虚基表的概念。

先记下来,以后再修改

C++对象的内存布局以及虚函数表和虚基表的更多相关文章

  1. C++虚函数表与虚析构函数

    1.静态联编和动态联编联编:将源代码中的函数调用解释为要执行函数代码. 静态联编:编译时能确定唯一函数.在C中,每个函数名都能确定唯一的函数代码.在C++中,因为有函数重载,编译器须根据函数名,参数才 ...

  2. C++ 中的虚函数表及虚函数执行原理

    为了实现虚函数,C++ 使用了虚函数表来达到延迟绑定的目的.虚函数表在动态/延迟绑定行为中用于查询调用的函数. 尽管要描述清楚虚函数表的机制会多费点口舌,但其实其本身还是比较简单的. 首先,每个包含虚 ...

  3. C++对象内存分布详解(包括字节对齐和虚函数表)

    转自:https://www.jb51.net/article/101122.htm 1.C++对象的内存分布和虚函数表: C++对象的内存分布和虚函数表注意,对象中保存的是虚函数表指针,而不是虚函数 ...

  4. C++ 关于类与对象在虚函数表上唯一性问题 浅析

    [摘要] 非常多教材上都有介绍到虚指针.虚函数与虚函数表.有的说类对象共享一个虚函数表,有的说,一个类对象拥有一个虚函数表.还有的说,不管用户声明了多少个类对象,可是,这个VTABLE虚函数表仅仅有一 ...

  5. 【C++ Primer | 15】C++虚函数表剖析②

    多重继承 下面,再让我们来看看多重继承中的情况,假设有下面这样一个类的继承关系. 注意:子类只overwrite了父类的f()函数,而还有一个是自己的函数(我们这样做的目的是为了用g1()作为一个标记 ...

  6. 深入分析C++虚函数表

    C++中的虚函数(Virtual Function)是用来实现动态多态性的,指的是当基类指针指向其派生类实例时,可以用基类指针调用派生类中的成员函数.如果基类指针指向不同的派生类,则它调用同一个函数就 ...

  7. C++虚函数与虚函数表

    多态性可分为两类:静态多态和动态多态.函数重载和运算符重载实现的多态属于静态多态,动态多态性是通过虚函数实现的. 每个含有虚函数的类有一张虚函数表(vtbl),表中每一项是一个虚函数的地址, 也就是说 ...

  8. 详谈C++虚函数表那回事(一般继承关系)

    沿途总是会出现关于C++虚函数表的问题,今天做一总结: 1.什么是虚函数表: 虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的.简称为V-Table. ...

  9. C++中的虚函数以及虚函数表

    一.虚函数的定义 被virtual关键字修饰的成员函数,目的是为了实现多态 ps: 关于多态[接口和实现分离,父类指针指向子类的实例,然后通过父类指针调用子类的成员函数,这样可以让父类指针拥有多种形态 ...

随机推荐

  1. ajax如何向后台传递数组,在后台该如何接收的问题(项目积累)

    一.后台如何接收从前台接收的数组: 使用request.getParameterValues(String xxx); <input type="text" name=&qu ...

  2. cassandra集群缩容与剔除问题节点

    今天在操作cassandra集群数据迁移时发生了一些意料之外的事情,服务器迁移前与迁移后同样为5台,但是不知道是什么原因导致的,迁移过后的节点居然多出了一台cassandra节点,个人瞬间感觉莫名其妙 ...

  3. Easy Ui 的reload 问题

    当我删除某条数据时,删除成功后要刷新datagrid 这时调用reload方法就不成功,而要用下面的方式. 正确代码$('#fixedGrid').datagrid("reload" ...

  4. spring mvc配置ObjectMapper忽略无法识别的字段,以及一些博客推荐

    通过Spring的MethodInvokingFactoryBean类实现的调用configure方法,此方法返回调用该方法的本身实例. 配置完毕后,可以在spring mvc的消息处理器中使用,为了 ...

  5. LeetCode142:Linked List Cycle II

    题目: Given a linked list, return the node where the cycle begins. If there is no cycle, return null. ...

  6. TransactionScope事务使用

    using (System.Transactions.TransactionScope T_Scope = new System.Transactions.TransactionScope()) { ...

  7. HttpWebRequest 模拟浏览器访问网站

    最近抓网页时报错: 要么返回 The remote server returned an error: (442)要么返回: 非法访问,您的行为已被WAF系统记录! 想了想,就当是人家加了抓网页的东西 ...

  8. js事件处理

    1.js中常用的事件处理程序(event Handler) onabort 用户终止了页面的加载 onblur 用户离开了对象 onchange 用户修改了对象 onclick 用户点击了对象 one ...

  9. A Tool to Clip Images

    using Microsoft.Win32; using System; using System.IO; using System.Text.RegularExpressions; using Sy ...

  10. 学习《精通数据科学从线性回归到深度学习》PDF+代码分析

    数据科学内容广泛,涉及到统计分析.机器学习以及计算机科学三方面的知识和技能.学习数据科学,推荐学习<精通数据科学从线性回归到深度学习>. 针对技术书籍,最好的阅读方法是对照每一章的示例代码 ...