zoukankan      html  css  js  c++  java
  • C++对象的内存布局以及虚函数表和虚基表

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

    本文为整理文章,

    参考:

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

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

     

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

     

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

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

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

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

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

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

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

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

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

     

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

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

    对于单继承

    Child类重写了Parentf()GrandChild类重写了Child类的f()g_child();

     

    GrandChild对象的内存布局为:


     

    可以看到:

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

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

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

    对于多继承


    Derive对象的内存布局


    可以看到:

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

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

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

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

    对于菱形继承问题


    D对象的内存布局


    可以看到

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

     

    对于虚继承


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

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

     



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

     

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

     

    先记下来,以后再修改

  • 相关阅读:
    java反射详解 (转至 http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html)
    DexClassLoader
    防止 apk反编译 jocky-- java混淆代码 (转至:http://my.oschina.net/f839903061/blog/72554)
    Android APK反编译详解(附图) (转至 http://blog.csdn.net/ithomer/article/details/6727581)
    双卡手机怎么指定SIM卡打电话
    android设备休眠
    GSON使用笔记(3) -- 如何反序列化出List
    Notepad++ 更换主题
    如何才能成为一个成功的项目经理
    项目经理是干出来的,不是学出来的;是带出来的,不是教出来的
  • 原文地址:https://www.cnblogs.com/qingergege/p/7610898.html
Copyright © 2011-2022 走看看