zoukankan      html  css  js  c++  java
  • C++对象内存布局 (二)

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

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

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

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

    源码如下:

    #include <iostream>
    using namespace std;
    
    class Parent
    {
    public:
        int iparent;
        Parent() : iparent(10) {}
        virtual void f()
        {
            cout << "Parent::f()" << endl;
        }
        virtual void g()
        {
            cout << "Parent::g()" << endl;
        }
    };
    
    class Child : virtual public Parent
    {
    public:
        int ichild;
        Child() : ichild(100) {}
        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 + 0);
        pf();
    
        cout << "    [0] 0x" << (Fun)*((int *)*(int *)&c + 1) << endl;
    
        cout << "[1] Child::vbptr->" << endl;
        cout << "    [0] " << *((int *)*((int *)&c + 1) + 0) << endl;
    
        cout << "    [1] " << *((int *)*((int *)&c + 1) + 1) << endl;
    
        cout << "    [2] " << *((int *)*((int *)&c + 1) + 2) << endl;
    
        cout << "[2] Child.ichild = " << (int)*((int *)&c + 2) << endl;
    
        cout << "[3] = 0x" << (int *)*((int *)&c + 3) << endl;
    
        cout << "[4] Parent::vfptr->" << endl;
        cout << "    [0] ";
        pf = (Fun)*((int *)*((int *)&c + 4) + 0);
        pf();
    
        cout << "    [1] ";
        pf = (Fun)*((int *)*((int *)&c + 4) + 1);
        pf();
        
        cout << "    [2] 0x" << (Fun)*((int *)*((int *)&c +4) + 2) << endl;
    
        cout << "[5] Parent.iparent = " << (int)*((int *)&c + 5) << endl;
        return 0;
    }

    代码运行结果如下:

    [0] Child::vfptr->
            [0] Child::g_child()
            [0] 0x00000000
    [1] Child::vbptr->
            [0] -4
            [1] 12
            [2] 0
    [2] Child.ichild = 100
    [3] = 0x00000000
    [4] Parent::vfptr->
            [0] Child::f()
            [1] Parent::g()
            [2] 0x00000000
    [5] Parent.iparent = 10

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

    由上图我们可以知道:

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

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

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

     

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

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

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

  • 相关阅读:
    最短路--floyd算法模板
    poj2367 拓扑序
    poj1094 拓扑序
    hdu3231 拓扑序
    hdu1811 并查集+拓扑序
    hdu3342 拓扑序
    hdu2647 拓扑序
    hdu1285 拓扑序
    UVA10305 拓扑序
    $.proxy
  • 原文地址:https://www.cnblogs.com/uangyy/p/4623320.html
Copyright © 2011-2022 走看看