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.在派生类和被虚拟继承的基类之间有一个空指针。

原文地址:https://www.cnblogs.com/uangyy/p/4623320.html