zoukankan      html  css  js  c++  java
  • c++ 对象的内存布局

    【本文链接】

    http://www.cnblogs.com/hellogiser/p/class-memory-layout.html

    【分析】

    对象的影响因素

    简而言之,一个类可能会有如下的影响因素:
    1)成员变量
    2)虚函数(产生虚函数表)
    3)单一继承(只继承于一个类)
    4)多重继承(继承多个类)
    5)重复继承(继承的多个父类中其父类有相同的超类)
    6)虚拟继承(使用virtual方式继承,为了保证继承后父类的内存布局只会存在一份)
    上述的东西通常是C++这门语言在语义方面对对象内部的影响因素,当然,还会有编译器的影响(比如优化),还有字节对齐的影响。在这里我们都不讨论,我们只讨论C++语言上的影响。

    本篇文章着重讨论下述几个情况下的C++对象的内存布局情况。

    1)单一的一般继承(带成员变量、虚函数、虚函数覆盖)
    2)单一的虚拟继承(带成员变量、虚函数、虚函数覆盖)
    3)多重继承(带成员变量、虚函数、虚函数覆盖)
    4)重复多重继承(带成员变量、虚函数、虚函数覆盖)
    5)钻石型的虚拟多重继承(带成员变量、虚函数、虚函数覆盖)

    (1)单一的一般继承

    下面,我们假设有如下所示的一个继承关系:

     

    请注意,在这个继承关系中,父类,子类,孙子类都有自己的一个成员变量。而了类覆盖了父类的f()方法,孙子类覆盖了子类的g_child()及其超类的f()。

    可见以下几个方面:
    1)虚函数表在最前面的位置。
    2)成员变量根据其继承和声明顺序依次放在后面。
    3)在单一的继承中,被override的虚函数在虚函数表中得到了更新。(Child的f覆盖Parent的f函数,然后GrandChild的f覆盖Child的f;GrandChild的g_child覆盖Child的g_child)

     代码验证如下

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
     
    /*
    version: 1.0
    author: hellogiser
    blog: http://www.cnblogs.com/hellogiser
    date: 2014/9/29
    */


    #include "stdafx.h"
    #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;
        }
        
    virtual void h()
        {
            cout << 
    " Parent::h()" << endl;
        }

    };

    class Child : public Parent
    {
    public:
        
    int ichild;
        Child(): ichild(
    100) {}
        
    virtual void f()
        {
            cout << 
    "Child::f()" << endl;
        }
        
    virtual void g_child()
        {
            cout << 
    "Child::g_child()" << endl;
        }
        
    virtual void h_child()
        {
            cout << 
    "Child::h_child()" << endl;
        }
    };

    class GrandChild : public Child
    {
    public:
        
    int igrandchild;
        GrandChild(): igrandchild(
    1000) {}
        
    virtual void f()
        {
            cout << 
    "GrandChild::f()" << endl;
        }
        
    virtual void g_child()
        {
            cout << 
    "GrandChild::g_child()" << endl;
        }
        
    virtual void h_grandchild()
        {
            cout << 
    "GrandChild::h_grandchild()" << endl;
        }
    };

    typedef void(*Fun)(void);

    /*
    vptr       ---> Parent::f(),Parent::g(),Parent::h()
    iparent
    */

    void test_parent()
    {
        Parent obj;
        Fun pFun;
        
    int **pVtab = (int **)(&obj);

        
    int n = 3;
        cout << 
    "[0] Parent::_vptr->" << endl;
        
    for (int i = 0; i < n; i++)
        {
            pFun = (Fun)pVtab[
    0][i];
            cout << 
    "------[" << i << "] ";
            pFun();
        }
        cout << 
    "[1] Parent.iparent = " << (int)pVtab[1] << endl;
        cout << 
    "============================================" << endl;
    }

    /*
    vptr       ---> Child::f(),Parent::g(),Parent::h(),Child::g_child(),Child::h_child()
    iparent
    ichild
    */

    void test_child()
    {
        Child obj;
        Fun pFun;
        
    int **pVtab = (int **)(&obj);

        
    int n = 5;
        cout << 
    "[0] Child::_vptr->" << endl;
        
    for (int i = 0; i < n; i++)
        {
            pFun = (Fun)pVtab[
    0][i];
            cout << 
    "------[" << i << "] ";
            pFun();
        }
        cout << 
    "[1] Parent.iparent = " << (int)pVtab[1] << endl;
        cout << 
    "[2] Child.ichild = " << (int)pVtab[2] << endl;
        
    //cout << "[3] GrandChild.igrandchild = " << (int)pVtab[3] << endl;
        cout << "============================================" << endl;
    }


    /*
    vptr       ---> GrandChild::f(),Parent::g(),Parent::h(),GrandChild::g_child(),Child::h_child()
    iparent
    ichild
    igrandchild
    */

    void test_grandchild()
    {
        GrandChild obj;
        Fun pFun;
        
    int **pVtab = (int **)(&obj);

        
    int n = 5;
        cout << 
    "[0] GrandChild::_vptr->" << endl;
        
    for (int i = 0; i < n; i++)
        {
            pFun = (Fun)pVtab[
    0][i];
            cout << 
    "------[" << i << "] ";
            pFun();
        }
        cout << 
    "[1] Parent.iparent = " << (int)pVtab[1] << endl;
        cout << 
    "[2] Child.ichild = " << (int)pVtab[2] << endl;
        cout << 
    "[3] GrandChild.igrandchild = " << (int)pVtab[3] << endl;
        cout << 
    "============================================" << endl;
    }

    int main()
    {
        test_parent();
        test_child();
        test_grandchild();
        
    return 0;
    }
    /*
    [0] Parent::_vptr->
    ------[0]  Parent::f()
    ------[1]  Parent::g()
    ------[2]  Parent::h()
    [1] Parent.iparent = 10
    ============================================
    [0] Child::_vptr->
    ------[0] Child::f()
    ------[1]  Parent::g()
    ------[2]  Parent::h()
    ------[3] Child::g_child()
    ------[4] Child::h_child()
    [1] Parent.iparent = 10
    [2] Child.ichild = 100
    ============================================
    [0] GrandChild::_vptr->
    ------[0] GrandChild::f()
    ------[1]  Parent::g()
    ------[2]  Parent::h()
    ------[3] GrandChild::g_child()
    ------[4] Child::h_child()
    [1] Parent.iparent = 10
    [2] Child.ichild = 100
    [3] GrandChild.igrandchild = 1000
    ============================================
    */

    (2)多重继承

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

    我们的类继承的源代码如下所示:父类的成员初始为10,20,30,子类的为100

    使用图片表示是下面这个样子:

    我们可以看到:
    1) 每个父类都有自己的虚表。
    2) 子类的成员函数被放到了第一个父类的表中。
    3) 内存布局中,其父类布局依次按声明顺序排列。
    4) 每个父类的虚表中的f()函数都被override成了子类的f()。这样做就是为了解决不同的父类类型的指针指向同一个子类实例,而能够调用到实际的函数。

    代码验证如下

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
     
    /*
    version: 1.0
    author: hellogiser
    blog: http://www.cnblogs.com/hellogiser
    date: 2014/9/29
    */


    #include "stdafx.h"
    #include <iostream>
    using namespace std;


    class Base1
    {
    public:
        
    int ibase1;
        Base1(): ibase1(
    10) {}
        
    virtual void f()
        {
            cout << 
    "Base1::f()" << endl;
        }
        
    virtual void g()
        {
            cout << 
    "Base1::g()" << endl;
        }
        
    virtual void h()
        {
            cout << 
    "Base1::h()" << endl;
        }

    };

    class Base2
    {
    public:
        
    int ibase2;
        Base2(): ibase2(
    20) {}
        
    virtual void f()
        {
            cout << 
    "Base2::f()" << endl;
        }
        
    virtual void g()
        {
            cout << 
    "Base2::g()" << endl;
        }
        
    virtual void h()
        {
            cout << 
    "Base2::h()" << endl;
        }
    };

    class Base3
    {
    public:
        
    int ibase3;
        Base3(): ibase3(
    30) {}
        
    virtual void f()
        {
            cout << 
    "Base3::f()" << endl;
        }
        
    virtual void g()
        {
            cout << 
    "Base3::g()" << endl;
        }
        
    virtual void h()
        {
            cout << 
    "Base3::h()" << endl;
        }
    };


    class Derive : public Base1, public Base2, public Base3
    {
    public:
        
    int iderive;
        Derive(): iderive(
    100) {}
        
    virtual void f()
        {
            cout << 
    "Derive::f()" << endl;
        }
        
    virtual void g1()
        {
            cout << 
    "Derive::g1()" << endl;
        }
    };

    typedef void(*Fun)(void);

    /*
    Base1 vptr---> Derive::f(),Base1::g(),Base1::h(),Derive::g1()
    ibase1
    Base2 vptr--->Derive::f(),Base2::g(),Base2::h()
    ibase2
    Base3 vptr--->Derive::f(),Base3::g(),Base3::h()
    ibase3
    iderive
    */

    void test()
    {
        Derive obj;
        Fun pFun;
        
    int **pVtab = (int **)(&obj);

        
    int n = 4;
        cout << 
    "[0] Base1::_vptr->" << endl;
        
    for (int i = 0; i < n; i++)
        {
            pFun = (Fun)pVtab[
    0][i];
            cout << 
    "------[" << i << "] ";
            pFun();
        }
        cout << 
    "[1] Base1.ibase1 = " << (int)pVtab[1] << endl;
        cout << 
    "============================================" << endl;
        n = 
    3;
        cout << 
    "[2] Base2::_vptr->" << endl;
        
    for (int i = 0; i < n; i++)
        {
            pFun = (Fun)pVtab[
    2][i];
            cout << 
    "------[" << i << "] ";
            pFun();
        }
        cout << 
    "[3] Base2.ibase2 = " << (int)pVtab[3] << endl;
        cout << 
    "============================================" << endl;
        n = 
    3;
        cout << 
    "[4] Base3::_vptr->" << endl;
        
    for (int i = 0; i < n; i++)
        {
            pFun = (Fun)pVtab[
    4][i];
            cout << 
    "------[" << i << "] ";
            pFun();
        }
        cout << 
    "[5] Base3.ibase3 = " << (int)pVtab[5] << endl;
        cout << 
    "============================================" << endl;
        cout << 
    "[6] Derive.iderive = " << (int)pVtab[6] << endl;
    }

    int main()
    {
        test();
        
    return 0;
    }
    /*
    [0] Base1::_vptr->
    ------[0] Derive::f()
    ------[1] Base1::g()
    ------[2] Base1::h()
    ------[3] Derive::g1()
    [1] Base1.ibase1 = 10
    ============================================
    [2] Base2::_vptr->
    ------[0] Derive::f()
    ------[1] Base2::g()
    ------[2] Base2::h()
    [3] Base2.ibase2 = 20
    ============================================
    [4] Base3::_vptr->
    ------[0] Derive::f()
    ------[1] Base3::g()
    ------[2] Base3::h()
    [5] Base3.ibase3 = 30
    ============================================
    [6] Derive.iderive = 100
    */
     

    (3)重复继承

    下面我们再来看看,发生重复继承的情况。所谓重复继承,也就是某个基类被间接地重复继承了多次。
    下图是一个继承图,我们重载了父类的f()函数。

    下面是对于子类实例中的虚函数表的图:

    我们可以看见,最顶端的父类B其成员变量存在于B1和B2中,并被D给继承下去了。而在D中,其有B1和B2的实例,于是B的成员在D的实例中存在两份,一份是B1继承而来的,另一份是B2继承而来的。所以,如果我们使用以下语句,则会产生二义性编译错误:

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
     
    void test_error()
    {
        D d;
        
    // d.ib = 1;    //ERROR
        d.B1::ib = 1;   // ok
        d.B2::ib = 100// ok
    }

    注意,上面例程中的最后两条语句存取的是两个变量。虽然我们消除了二义性的编译错误,但B类在D中还是有两个实例,这种继承造成了数据的重复,我们叫这种继承为重复继承。重复的基类数据成员可能并不是我们想要的。所以,C++引入了虚基类的概念。 

    代码验证如下

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
     
    /*
    version: 1.0
    author: hellogiser
    blog: http://www.cnblogs.com/hellogiser
    date: 2014/9/29
    */


    #include "stdafx.h"
    #include <iostream>
    using namespace std;


    class B
    {
    public:
        
    int ib;
        
    char cb;
    public:
        B(): ib(
    0), cb('B') {}

        
    virtual void f()
        {
            cout << 
    "B::f()" << endl;
        }
        
    virtual void Bf()
        {
            cout << 
    "B::Bf()" << endl;
        }
    };

    class B1 :  public B
    {
    public:
        
    int ib1;
        
    char cb1;
    public:
        B1(): ib1(
    11), cb1('1') {}

        
    virtual void f()
        {
            cout << 
    "B1::f()" << endl;
        }
        
    virtual void f1()
        {
            cout << 
    "B1::f1()" << endl;
        }
        
    virtual void Bf1()
        {
            cout << 
    "B1::Bf1()" << endl;
        }

    };

    class B2:  public B
    {
    public:
        
    int ib2;
        
    char cb2;
    public:
        B2(): ib2(
    12), cb2('2') {}

        
    virtual void f()
        {
            cout << 
    "B2::f()" << endl;
        }
        
    virtual void f2()
        {
            cout << 
    "B2::f2()" << endl;
        }
        
    virtual void Bf2()
        {
            cout << 
    "B2::Bf2()" << endl;
        }

    };

    class D : public B1, public B2
    {
    public:
        
    int id;
        
    char cd;
    public:
        D(): id(
    100), cd('D') {}

        
    virtual void f()
        {
            cout << 
    "D::f()" << endl;
        }
        
    virtual void f1()
        {
            cout << 
    "D::f1()" << endl;
        }
        
    virtual void f2()
        {
            cout << 
    "D::f2()" << endl;
        }
        
    virtual void Df()
        {
            cout << 
    "D::Df()" << endl;
        }

    };

    typedef void(*Fun)(void);


    void test_error()
    {
        D d;
        
    // d.ib = 1;    //ERROR
        d.B1::ib = 1;   // ok
        d.B2::ib = 100// ok
    }

    /*
    B1.vptr --->D::f,B::Bf,D::f1,B1::Bf1,D::Df
    B.ib
    B.cb
    B1.ib1
    B1.cb1

    B2.vptr --->D::f,B::Bf,D::f2,B2::Bf2
    B.ib
    B.cb
    B2.ib2
    B2.cb2

    D.id
    D.cd
    */

    void test_public()
    {
        D obj;
        Fun pFun;
        
    int **pVtab = (int **)(&obj);

        
    int n = 5;
        cout << 
    "[0] D::B1::_vptr->" << endl;
        
    for (int i = 0; i < n; i++)
        {
            pFun = (Fun)pVtab[
    0][i];
            cout << 
    "------[" << i << "] ";
            pFun();
        }
        cout << 
    "[1] B.ib = " << (int)pVtab[1] << endl;
        cout << 
    "[2] B.cb = " << (char)pVtab[2] << endl;
        cout << 
    "[3] B1.ib1 = " << (int)pVtab[3] << endl;
        cout << 
    "[4] B1.cb1 = " << (char)pVtab[4] << endl;

        n = 
    4;
        cout << 
    "[5] D::B2::_vptr->" << endl;
        
    for (int i = 0; i < n; i++)
        {
            pFun = (Fun)pVtab[
    5][i];
            cout << 
    "------[" << i << "] ";
            pFun();
        }
        cout << 
    "[6] B.ib = " << (int)pVtab[6] << endl;
        cout << 
    "[7] B.cb = " << (char)pVtab[7] << endl;
        cout << 
    "[8] B2.ib2 = " << (int)pVtab[8] << endl;
        cout << 
    "[9] B2.cb2 = " << (char)pVtab[9] << endl;

        cout << 
    "[10] D.id = " << (int)pVtab[10] << endl;
        cout << 
    "[11] D.cd = " << (char)pVtab[11] << endl;
    }

    void test_virtual_public()
    {

    }

    int main()
    {
        test_public();
        
    return 0;
    }
    /*
    [0] D::B1::_vptr->
    ------[0] D::f()
    ------[1] B::Bf()
    ------[2] D::f1()
    ------[3] B1::Bf1()
    ------[4] D::Df()
    [1] B.ib = 0
    [2] B.cb = B
    [3] B1.ib1 = 11
    [4] B1.cb1 = 1
    [5] D::B2::_vptr->
    ------[0] D::f()
    ------[1] B::Bf()
    ------[2] D::f2()
    ------[3] B2::Bf2()
    [6] B.ib = 0
    [7] B.cb = B
    [8] B2.ib2 = 12
    [9] B2.cb2 = 2
    [10] D.id = 100
    [11] D.cd = D
    */

    (4)钻石型多重虚拟继承

    虚拟继承的出现就是为了解决重复继承中多个间接父类的问题的。钻石型的结构是其最经典的结构。也是我们在这里要讨论的结构:

    上述的“重复继承”只需要把B1和B2继承B的语法中加上virtual 关键,就成了虚拟继承,其继承图如下所示:

     

    上图和前面的“重复继承”中的类的内部数据和接口都是完全一样的,只是我们采用了虚拟继承:其省略后的源码如下所示:

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     
    class B
    {
        ……
    };
    class B1 : virtual public B
    {
        ……
    };
    class B2: virtual public B
    {
        ……
    };
    class D : public B1, public B2
    {
        ……
    };

    代码验证如下

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
     
    /*
    version: 1.0
    author: hellogiser
    blog: http://www.cnblogs.com/hellogiser
    date: 2014/9/29
    */


    #include "stdafx.h"
    #include <iostream>
    using namespace std;


    class B
    {
    public:
        
    int ib;
        
    char cb;
    public:
        B(): ib(
    0), cb('B') {}

        
    virtual void f()
        {
            cout << 
    "B::f()" << endl;
        }
        
    virtual void Bf()
        {
            cout << 
    "B::Bf()" << endl;
        }
    };

    class B1 : virtual  public B
    {
    public:
        
    int ib1;
        
    char cb1;
    public:
        B1(): ib1(
    11), cb1('1') {}

        
    virtual void f()
        {
            cout << 
    "B1::f()" << endl;
        }
        
    virtual void f1()
        {
            cout << 
    "B1::f1()" << endl;
        }
        
    virtual void Bf1()
        {
            cout << 
    "B1::Bf1()" << endl;
        }

    };

    class B2: virtual  public B
    {
    public:
        
    int ib2;
        
    char cb2;
    public:
        B2(): ib2(
    12), cb2('2') {}

        
    virtual void f()
        {
            cout << 
    "B2::f()" << endl;
        }
        
    virtual void f2()
        {
            cout << 
    "B2::f2()" << endl;
        }
        
    virtual void Bf2()
        {
            cout << 
    "B2::Bf2()" << endl;
        }

    };

    class D : public B1, public B2
    {
    public:
        
    int id;
        
    char cd;
    public:
        D(): id(
    100), cd('D') {}

        
    virtual void f()
        {
            cout << 
    "D::f()" << endl;
        }
        
    virtual void f1()
        {
            cout << 
    "D::f1()" << endl;
        }
        
    virtual void f2()
        {
            cout << 
    "D::f2()" << endl;
        }
        
    virtual void Df()
        {
            cout << 
    "D::Df()" << endl;
        }

    };

    typedef void(*Fun)(void);


    void test_error()
    {
        D d;
        d.ib = 
    1;    //OK
    }

    /*
    B1.vptr --->D::f1,B1::Bf1,D::Df
    B1.vbptr (-4)
    B1.ib1
    B1.cb1

    B2.vptr --->D::f2,B2::Bf2
    B2.vbptr  (-4)
    B2.ib2
    B2.cb2

    D.id
    D.cd
    NULL      (delimiter)
    B.vptr --->D::f,B::Bf
    B.ib
    B.cb
    */

    void test_virtual_public()
    {
        D obj;
        Fun pFun;
        
    int **pVtab = (int **)(&obj);

        
    int n = 3;
        cout << 
    "[0] D::B1::_vptr->" << endl;
        
    for (int i = 0; i < n; i++)
        {
            pFun = (Fun)pVtab[
    0][i];
            cout << 
    "------[" << i << "] ";
            pFun();
        }
        cout << 
    "[1] B1::_vbptr = " << (int)pVtab[1] << " " << *pVtab[1] << endl;
        cout << 
    "[2] B1.ib1 = " << (int)pVtab[2] << endl;
        cout << 
    "[3] B1.cb1 = " << (char)pVtab[3] << endl;

        n = 
    2;
        cout << 
    "[4] D::B2::_vptr->" << endl;
        
    for (int i = 0; i < n; i++)
        {
            pFun = (Fun)pVtab[
    4][i];
            cout << 
    "------[" << i << "] ";
            pFun();
        }
        cout << 
    "[5] B2::_vbptr = " << (int)pVtab[5] << " " << *pVtab[5] << endl;
        cout << 
    "[6] B2.ib2 = " << (int)pVtab[6] << endl;
        cout << 
    "[7] B2.cb2 = " << (char)pVtab[7] << endl;

        cout << 
    "[8] D.id = " << (int)pVtab[8] << endl;
        cout << 
    "[9] D.cd = " << (char)pVtab[9] << endl;

        cout << 
    "[10] NULL =0x " << pVtab[10] << endl;

        n = 
    2;
        cout << 
    "[11] D::B::_vptr->" << endl;
        
    for (int i = 0; i < n; i++)
        {
            pFun = (Fun)pVtab[
    11][i];
            pFun();
        }
        cout << 
    "[12] B.ib = " << (int)pVtab[12] << endl;
        cout << 
    "[13] B.cb = " << (char)pVtab[13] << endl;
    }


    int main()
    {
        test_virtual_public();
        
    return 0;
    }

    /*
    [0] D::B1::_vptr->
    ------[0] D::f1()
    ------[1] B1::Bf1()
    ------[2] D::Df()
    [1] B1::_vbptr = 10769056 -4
    [2] B1.ib1 = 11
    [3] B1.cb1 = 1
    [4] D::B2::_vptr->
    ------[0] D::f2()
    ------[1] B2::Bf2()
    [5] B2::_vbptr = 10769048 -4
    [6] B2.ib2 = 12
    [7] B2.cb2 = 2
    [8] D.id = 100
    [9] D.cd = D
    [10] NULL =0x 00000000
    [11] D::B::_vptr->
    D::f()
    B::Bf()
    [12] B.ib = 0
    [13] B.cb = B
    */

    从上述结果,我们可以看出,B1和B2的继承方式改为virtual继承之后,内存布局发生了3个重大变化:

    1) 首先B1,然后是B2,接着是D,而B这个超类的实例都放在最后的位置(B1和B2的公共部分B被提取出来放在D实例的最后)

    2) B1和B2的vptr之后添加了一个字段vbptr,其值为-4(表示vptr相对vbptr地址的偏移量)

    3)在D和最后的B之间添加了一个NULL分隔符将其布局分开。(只有派生类覆盖了基类的virtual函数,才有分隔符,否则没有分隔符)


     【附录】

    (1)单一继承vs单一virtual继承

    【单一继承】

     public inheritance
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
     
    /*
    version: 1.0
    author: hellogiser
    blog: http://www.cnblogs.com/hellogiser
    date: 2014/9/29
    */


    #include "stdafx.h"
    #include <iostream>
    using namespace std;

    class Base
    {
    public:
        
    int ibase;
    public:
        Base(): ibase(
    10) {}

        
    virtual void f()
        {
            cout << 
    "Base::f()" << endl;
        }
        
    virtual void g()
        {
            cout << 
    "Base::g()" << endl;
        }
        
    virtual void h()
        {
            cout << 
    "Base::h()" << endl;
        }
    };

    class Derived : public Base
    {
    public:
        
    int iderived;
    public:
        Derived(): iderived(
    100) {}

        
    virtual void f()
        {
            cout << 
    "Derived::f()" << endl;
        }
        
    virtual void g2()
        {
            cout << 
    "Derived::g2()" << endl;
        }
        
    virtual void h2()
        {
            cout << 
    "Derived::h2()" << endl;
        }
    };

    typedef void(*Fun)(void);


    /*
    Base::vptr--->Derived::f(),Base::g(),Base::h(),Derived::g2(),Derived::h2()
    ibase
    iderived
    */

    void test_public()
    {
        Derived obj;
        Fun pFun;
        
    int **pVtab = (int **)(&obj);

        
    int n = 5;
        cout << 
    "[0] Base::_vptr->" << endl;
        
    for (int i = 0; i < n; i++)
        {
            pFun = (Fun)pVtab[
    0][i];
            cout << 
    "------[" << i << "] ";
            pFun();
        }
        cout << 
    "[1] Base.ibase = " << (int)pVtab[1] << endl;
        cout << 
    "[2] Derived.iderived = " << (int)pVtab[2] << endl;
    }

    int main()
    {
        test_public();
        
    return 0;
    }
    /*
    [0] Base::_vptr->
    ------[0] Derived::f()
    ------[1] Base::g()
    ------[2] Base::h()
    ------[3] Derived::g2()
    ------[4] Derived::h2()
    [1] Base.ibase = 10
    [2] Derived.iderived = 100
    */

    【单一virtual继承】

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
     
    /*
    version: 1.0
    author: hellogiser
    blog: http://www.cnblogs.com/hellogiser
    date: 2014/9/29
    */


    #include "stdafx.h"
    #include <iostream>
    using namespace std;

    class Base
    {
    public:
        
    int ibase;
    public:
        Base(): ibase(
    10) {}

        
    virtual void f()
        {
            cout << 
    "Base::f()" << endl;
        }
        
    virtual void g()
        {
            cout << 
    "Base::g()" << endl;
        }
        
    virtual void h()
        {
            cout << 
    "Base::h()" << endl;
        }
    };

    class Derived : virtual public Base
    {
    public:
        
    int iderived;
    public:
        Derived(): iderived(
    100) {}

        
    virtual void f()
        {
            cout << 
    "Derived::f()" << endl;
        }
        
    virtual void g2()
        {
            cout << 
    "Derived::g2()" << endl;
        }
        
    virtual void h2()
        {
            cout << 
    "Derived::h2()" << endl;
        }
    };

    typedef void(*Fun)(void);


    /*
    Derived::vptr--->Derived::g2(),Derived::h2()
    Derived::vbptr
    iderived

    NULL  (demiliter)
    Base::vptr--->Derived::f(),Base::g(),Base::h()
    ibase
    */

    void test_virtual_public()
    {
        Derived obj;
        Fun pFun;
        
    int **pVtab = (int **)(&obj);

        
    int n = 2;
        cout << 
    "[0] Derived::_vptr->" << endl;
        
    for (int i = 0; i < n; i++)
        {
            pFun = (Fun)pVtab[
    0][i];
            cout << 
    "------[" << i << "] ";
            pFun();
        }
        cout << 
    "[1] Derived::_vbptr = " << (int)pVtab[1] << " " << *pVtab[1] << endl;
        cout << 
    "[2] Derived.iderived = " << (int)pVtab[2] << endl;

        cout << 
    "[3] NULL =0x " << pVtab[3] << endl;

        n = 
    3;
        cout << 
    "[4] Base::_vptr->" << endl;
        
    for (int i = 0; i < n; i++)
        {
            pFun = (Fun)pVtab[
    4][i];
            pFun();
        }
        cout << 
    "[5] Base.ibase = " << (int)pVtab[5] << endl;

    }

    int main()
    {
        test_virtual_public();
        
    return 0;
    }
    /*
    [0] Derived::_vptr->
    ------[0] Derived::g2()
    ------[1] Derived::h2()
    [1] Derived::_vbptr = 17449756 -4
    [2] Derived.iderived = 100
    [3] NULL =0x 00000000
    [4] Base::_vptr->
    Derived::f()
    Base::g()
    Base::h()
    [5] Base.ibase = 10
    */

    (2)单一virtual继承的4种情况

    假设Base有3个虚函数f,g,h

    1)Derived没有覆盖基类Base的任何虚函数,Derived没有定义新的虚函数,内存布局如下

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     

    //virtual void f() { cout << "Derived::f()" << endl;}
    //virtual void g2() { cout << "Derived::g2()" << endl;}
    //virtual void h2() { cout << "Derived::h2()" << endl;}

    /*
    [0] Derived::_vbptr = 19088092 0
    [1] Derived.iderived = 100
    [2] Base::_vptr->
    Base::f()
    Base::g()
    Base::h()
    [3] Base.ibase = 10
    */

    2)Derived没有覆盖基类Base的任何虚函数,但是Derived定义了新的虚函数g2和h2,内存布局如下

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     

    //virtual void f() { cout << "Derived::f()" << endl;}
    virtual void g2()
    {
        cout << 
    "Derived::g2()" << endl;
    }
    virtual void h2()
    {
        cout << 
    "Derived::h2()" << endl;
    }

    /*
    [0] Derived::_vptr ->
    Derived::g2()
    Derived::h2()
    [1] Derived::_vbptr = 20857576 -4
    [2] Derived.iderived = 100
    [3] Base::_vptr->
    Base::f()
    Base::g()
    Base::h()
    [4] Base.ibase = 10
    */

    3)Derived覆盖了基类Base的某个虚函数f,但是Derived没有定义新的虚函数,内存布局如下

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     

    virtual void f()
    {
        cout << 
    "Derived::f()" << endl;
    }
    //virtual void g2() { cout << "Derived::g2()" << endl;}
    //virtual void h2() { cout << "Derived::h2()" << endl;}

    /*
    [0] Derived::_vbptr = 11748060 0
    [1] Derived.iderived = 100
    [2] NULL =0x 00000000
    [3] Base::_vptr->
    Derived::f()
    Base::g()
    Base::h()
    [4] Base.ibase = 10
    */

    4)Derived覆盖了基类Base的某个虚函数f,同时Derived定义了新的虚函数g2和h2,内存布局如下

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     

    virtual void f()
    {
        cout << 
    "Derived::f()" << endl;
    }
    virtual void g2()
    {
        cout << 
    "Derived::g2()" << endl;
    }
    virtual void h2()
    {
        cout << 
    "Derived::h2()" << endl;
    }

    /*
    [0] Derived::_vptr ->
        Derived::g2()
        Derived::h2()
    [1] Derived::_vbptr = 10441448 -4
    [2] Derived.iderived = 100
    [3] NULL =0x 00000000
    [4] Base::_vptr->
        Derived::f()
        Base::g()
        Base::h()
    [5] Base.ibase = 10
    */

    由此可见:

    Derived是否覆盖Base的虚函数?

    1)Derived没有覆盖基类Base的任何虚函数,内存布局中Derived和Base部分没有分隔符NULL。

    2)Derived覆盖基类Base的某个虚函数f,内存布局中Derived和Base部分添加了分隔符NULL。

    Derived是否定义新的虚函数?

    1)Derived定义了新的虚函数g2和h2,内存布局的前2个位置依次为vfptr和vbptr,且vbptr的值为-4,表示vfptr和vbptr的偏移量为-4

    2)Derived没有定义新的虚函数,内存布局的vfptr和vbptr退化为一个,且vbptr的值为0,表示vfptr和vbptr的偏移量为0,即vfptr和vbptr重合了。

    完整代码如下

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
     
    /*
    version: 1.0
    author: hellogiser
    blog: http://www.cnblogs.com/hellogiser
    date: 2014/9/29
    */


    #include "stdafx.h"
    #include <iostream>
    using namespace std;

    class Base
    {
    public:
        
    int ibase;
    public:
        Base(): ibase(
    10) {}

        
    virtual void f()
        {
            cout << 
    "Base::f()" << endl;
        }
        
    virtual void g()
        {
            cout << 
    "Base::g()" << endl;
        }
        
    virtual void h()
        {
            cout << 
    "Base::h()" << endl;
        }
    };

    class Derived : virtual public Base
    {
    public:
        
    int iderived;
    public:
        Derived(): iderived(
    100) {}

        
    virtual void f()
        {
            cout << 
    "Derived::f()" << endl;
        }
        
    virtual void g2()
        {
            cout << 
    "Derived::g2()" << endl;
        }
        
    virtual void h2()
        {
            cout << 
    "Derived::h2()" << endl;
        }
    };

    typedef void(*Fun)(void);


    /*
    //virtual void f() { cout << "Derived::f()" << endl;}
    //virtual void g2() { cout << "Derived::g2()" << endl;}
    //virtual void h2() { cout << "Derived::h2()" << endl;}
    */


    /*
    [0] Derived::_vbptr = 19088092 0
    [1] Derived.iderived = 100
    [2] Base::_vptr->
    Base::f()
    Base::g()
    Base::h()
    [3] Base.ibase = 10
    */

    void test_virtual_public_1()
    {
        Derived obj;
        Fun pFun;
        
    int **pVtab = (int **)(&obj);

        
    int n = 0;
        cout << 
    "[0] Derived::_vbptr = " << (int)pVtab[0] << " " << *pVtab[0] << endl;
        cout << 
    "[1] Derived.iderived = " << (int)pVtab[1] << endl;

        n = 
    3;
        cout << 
    "[2] Base::_vptr->" << endl;
        
    for (int i = 0; i < n; i++)
        {
            pFun = (Fun)pVtab[
    2][i];
            pFun();
        }
        cout << 
    "[3] Base.ibase = " << (int)pVtab[3] << endl;

    }

    /*
    //virtual void f() { cout << "Derived::f()" << endl;}
    virtual void g2() { cout << "Derived::g2()" << endl;}
    virtual void h2() { cout << "Derived::h2()" << endl;}
    */


    /*
    [0] Derived::_vptr ->
    Derived::g2()
    Derived::h2()
    [1] Derived::_vbptr = 20857576 -4
    [2] Derived.iderived = 100
    [3] Base::_vptr->
    Base::f()
    Base::g()
    Base::h()
    [4] Base.ibase = 10
    */

    void test_virtual_public_2()
    {
        Derived obj;
        Fun pFun;
        
    int **pVtab = (int **)(&obj);

        
    int n = 2;
        cout << 
    "[0] Derived::_vptr ->" << endl;
        
    for (int i = 0; i < n; i++)
        {
            pFun = (Fun)pVtab[
    0][i];
            pFun();
        }
        cout << 
    "[1] Derived::_vbptr = " << (int)pVtab[1] << " " << *pVtab[1] << endl;
        cout << 
    "[2] Derived.iderived = " << (int)pVtab[2] << endl;

        n = 
    3;
        cout << 
    "[3] Base::_vptr->" << endl;
        
    for (int i = 0; i < n; i++)
        {
            pFun = (Fun)pVtab[
    3][i];
            pFun();
        }
        cout << 
    "[4] Base.ibase = " << (int)pVtab[4] << endl;

    }

    /*
    virtual void f() { cout << "Derived::f()" << endl;}
    //virtual void g2() { cout << "Derived::g2()" << endl;}
    //virtual void h2() { cout << "Derived::h2()" << endl;}
    */


    /*
    [0] Derived::_vbptr = 11748060 0
    [1] Derived.iderived = 100
    [2] NULL =0x 00000000
    [3] Base::_vptr->
    Derived::f()
    Base::g()
    Base::h()
    [4] Base.ibase = 10
    */

    void test_virtual_public_3()
    {
        Derived obj;
        Fun pFun;
        
    int **pVtab = (int **)(&obj);

        
    int n = 0;
        cout << 
    "[0] Derived::_vbptr = " << (int)pVtab[0] << " " << *pVtab[0] << endl;
        cout << 
    "[1] Derived.iderived = " << (int)pVtab[1] << endl;

        cout << 
    "[2] NULL =0x " << pVtab[2] << endl;

        n = 
    3;
        cout << 
    "[3] Base::_vptr->" << endl;
        
    for (int i = 0; i < n; i++)
        {
            pFun = (Fun)pVtab[
    3][i];
            pFun();
        }
        cout << 
    "[4] Base.ibase = " << (int)pVtab[4] << endl;
    }


    /*
    virtual void f() { cout << "Derived::f()" << endl;}
    virtual void g2() { cout << "Derived::g2()" << endl;}
    virtual void h2() { cout << "Derived::h2()" << endl;}
    */


    /*
    [0] Derived::_vptr ->
        Derived::g2()
        Derived::h2()
    [1] Derived::_vbptr = 10441448 -4
    [2] Derived.iderived = 100
    [3] NULL =0x 00000000
    [4] Base::_vptr->
        Derived::f()
        Base::g()
        Base::h()
    [5] Base.ibase = 10
    */

    void test_virtual_public_4()
    {
        Derived obj;
        Fun pFun;
        
    int **pVtab = (int **)(&obj);

        
    int n = 2;
        cout << 
    "[0] Derived::_vptr ->" << endl;
        
    for (int i = 0; i < n; i++)
        {
            pFun = (Fun)pVtab[
    0][i];
            pFun();
        }
        cout << 
    "[1] Derived::_vbptr = " << (int)pVtab[1] << " " << *pVtab[1] << endl;
        cout << 
    "[2] Derived.iderived = " << (int)pVtab[2] << endl;

        cout << 
    "[3] NULL =0x " << pVtab[3] << endl;

        n = 
    3;
        cout << 
    "[4] Base::_vptr->" << endl;
        
    for (int i = 0; i < n; i++)
        {
            pFun = (Fun)pVtab[
    4][i];
            pFun();
        }
        cout << 
    "[5] Base.ibase = " << (int)pVtab[5] << endl;

    }

    int main()
    {
        test_virtual_public_4();
        
    return 0;
    }

    【参考】

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

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

  • 相关阅读:
    导数,微积分,牛顿运动学制作创意地图
    逻辑回归的算法思想
    偏导数
    POJ2112:Optimal Milking(Floyd+二分图多重匹配+二分)
    POJ2289:Jamie's Contact Groups(二分+二分图多重匹配)
    HDU3829:Cat VS Dog(最大独立集)
    POJ2594:Treasure Exploration(Floyd + 最小路径覆盖)
    HDU1151:Air Raid(最小边覆盖)
    HDU1054 Strategic Game(最小点覆盖)
    POJ3020:Antenna Placement(二分图匹配)
  • 原文地址:https://www.cnblogs.com/hellogiser/p/class-memory-layout.html
Copyright © 2011-2022 走看看