您的位置:首页 > 编程语言 > C语言/C++

跟我一起学习C++虚函数--第四篇

2012-07-18 12:51 85 查看
在前一篇,我们讨论了在多继承情况下,具有虚函数的类的内存布局情况。本篇将进一步探索在多重继承,即具有重复继承的情况下的内存布局情况。在阅读本篇和下一篇之前,建议先阅读本博客另一篇博文《浅析GCC下C++多重继承
&虚拟继承的对象内存布局》。

先说一点题外话,细心的读者可能会发现,我们在探索不同情况下类的内存布局时,总是先通过查看类的大小以及其中各个成员变量的地址来进行分析,然后再具体定位某一位置的值。从最原始的内存中的对象分布,我们可以获得最深入最有效的理解。

OK,请看例子:

01
#include
<iostream>
02
using
namespace
std;
03
04
class
Top
05
{
06
public
:
07
virtual
void
x(){cout
<<
"top
x"
<<
endl;}
08
virtual
void
print0(){cout
<<
"top
print"
<<
endl;}
09
public
:
10
int
a;
11
};
12
13
class
Left:
public
Top
14
{
15
public
:
16
virtual
void
y(){cout
<<
"left
y"
<<
endl;}
17
virtual
void
print1(){cout
<<
"left
print"
<<
endl;}
18
public
:
19
int
b;
20
};
21
22
class
Right:
public
Top
23
{
24
public
:
25
virtual
void
z(){cout
<<
"right
z"
<<
endl;}
26
virtual
void
print2(){cout
<<
"right
print"
<<
endl;}
27
public
:
28
int
c;
29
};
30
31
class
Bottom
:
public
Left,
public
Right
32
{
33
public
:
34
virtual
void
y(){cout
<<
"bottom
y"
<<
endl;}
35
virtual
void
z(){cout
<<
"bottom
z"
<<
endl;}
36
virtual
void
print3(){cout
<<
"bottom
print"
<<
endl;}
37
public
:
38
int
d;
39
};
40
41
int
main()
42
{
43
/*first
part*/
44
cout
<<
sizeof
(Top)
<<
"\t"
<<
sizeof
(Left)
<<
"\t"
<<
sizeof
(Right)
<<
"\t"
<<
sizeof
(Bottom)
<<endl;
45
//输出:8
121228
46
Bottom
*b=
new
Bottom();
47
cout
<<b<<
"
"
<<
&b->Left::a<<
"
"
<<
&b->b<<
"
"
<<
&b->Right::a<<
"
"
<<
&b->c<<
"
"
<<
&b->d<<endl;
48
//输出:0x8c0f008
0x8c0f00c0x8c0f0100x8c0f0180x8c0f01c0x8c0f020
49
50
/*second
part*/
51
typedef
void
(*Func)(
void
);
52
Func
pFunc;
53
pFunc
=(Func)*((
int
*)*(
int
*)(b));
54
pFunc();
//输出:top
x
55
pFunc
=(Func)*((
int
*)*(
int
*)(b)+1);
56
pFunc();
//输出:top
print
57
pFunc
=(Func)*((
int
*)*(
int
*)(b)+2);
58
pFunc();
//输出:bottom
y
59
pFunc
=(Func)*((
int
*)*(
int
*)(b)+3);
60
pFunc();
//输出:left
print
61
pFunc
=(Func)*((
int
*)*(
int
*)(b)+4);
62
pFunc();
//输出:bottom
z
63
pFunc
=(Func)*((
int
*)*(
int
*)(b)+5);
64
pFunc();
//输出:bottom
print
65
//pFunc
=(Func)*((int*)*(int*)(b)+6);
66
//pFunc();//段错误
67
68
/*third
part*/
69
pFunc
=(Func)*((
int
*)*((
int
*)(b)+3));
70
pFunc();
//输出:top
x
71
pFunc
=(Func)*((
int
*)*((
int
*)(b)+3)+1);
72
pFunc();
//输出:top
print
73
pFunc
=(Func)*((
int
*)*((
int
*)(b)+3)+2);
74
pFunc();
//输出:bottom
z
75
pFunc
=(Func)*((
int
*)*((
int
*)(b)+3)+3);
76
pFunc();
//输出:right
print
77
//pFunc
=(Func)*((int*)*((int*)(b)+3)+4);
78
//pFunc();//段错误
79
80
delete
b;
81
return
0;
82
}
对于上面的例子,我们分为三部分进行讲解。

第一部分:多重继承情况下,对象本身(除虚函数表外)的内存布局。

从代码中firstpart的输出情况来看,Top、Left和Right的大小很容易理解,至于Bottom类的大小,如果你看过参考文献一,那么也很容易理解。Bottom类包含了两次Top类中的a成员变量,因此总共有5个int成员变量,为20字节。再加上两个虚指针,即为28字节。

从输出的Bottom对象中成员变量地址情况,我们可以用如下图来表示内存布局:



简单地说,多重继承时,子类会有多个祖父类的存在。

第二部分:多重继承情况下,主要虚函数表的内存布局。

从代码的secondpart的输出情况来看,我们可以用下图来表示主要虚函数表的内存布局:



第三部分:多重继承情况下,次要虚函数表的内存布局。

从代码的thirdpart的输出情况来看,我们可以用下图来表示次要虚函数表的内存布局:



对比前一篇多继承情况下类的内存布局,我们可以发现:在多重继承情况下,不仅祖父类的成员变量在子类中会有多份存在,祖父类的虚函数同样会在子类的虚函数表中有多份存在,分别位于主要虚函数表和次要虚函数表中。

参考文献:

1.《浅析GCC下C++多重继承&虚拟继承的对象内存布局》

2.《深度探索C++对象模型》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: