首页 > 代码库 > c++ 对象的内存布局

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

c++ 对象的内存布局