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

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

2012-07-18 12:50 295 查看
上一篇我们讨论了在单一继承的情况下,具有虚函数的类对象的内存布局情况。本篇主要讨论在多继承情况下,对象的内存布局。

看例子:

01
#include
<iostream>
02
using
namespace
std;
03
04
class
Left
05
{
06
public
:
07
virtual
void
x(){cout
<<
"left
x"
<<
endl;}
08
virtual
void
print1(){cout
<<
"left
print"
<<
endl;}
09
public
:
10
int
a;
11
};
12
13
class
Right
14
{
15
public
:
16
virtual
void
y(){cout
<<
"right
y"
<<
endl;}
17
virtual
void
print2(){cout
<<
"right
print"
<<
endl;}
18
public
:
19
int
b;
20
};
21
22
class
Bottom
:
public
Left,
public
Right
23
{
24
public
:
25
virtual
void
x(){cout
<<
"bottom
x"
<<
endl;}
26
virtual
void
y(){cout
<<
"bottom
y"
<<
endl;}
27
virtual
void
print3(){cout
<<
"bottom
print"
<<
endl;}
28
public
:
29
int
c;
30
};
31
32
int
main()
33
{
34
/*first
part*/
35
cout
<<
sizeof
(Left)
<<
"\t"
<<
sizeof
(Right)
<<
"\t"
<<
sizeof
(Bottom)
<<endl;
//输出:8
820
36
Bottom
*b=
new
Bottom();
37
cout
<<b<<
"
"
<<
&b->a<<
"
"
<<
&b->b<<
"
"
<<
&b->c<<endl;
38
//输出:0x8af6008
0x8af600c0x8af60140x8af6018
39
40
/*second
part*/
41
typedef
void
(*Func)(
void
);
42
Func
pFunc;
43
pFunc
=(Func)*((
int
*)*(
int
*)(b));
44
pFunc();
//输出:bottom
x
45
pFunc
=(Func)*((
int
*)*(
int
*)(b)+1);
46
pFunc();
//输出:left
print
47
pFunc
=(Func)*((
int
*)*(
int
*)(b)+2);
48
pFunc();
//输出:bottom
y
49
pFunc
=(Func)*((
int
*)*(
int
*)(b)+3);
50
pFunc();
//输出:bottom
print
51
//pFunc
=(Func)*((int*)*(int*)(b)+4);
52
//pFunc();//段错误
53
54
55
/*third
part*/
56
pFunc
=(Func)*((
int
*)*((
int
*)(b)+2));
57
pFunc();
//输出:bottom
y
58
pFunc
=(Func)*((
int
*)*((
int
*)(b)+2)+1);
59
pFunc();
//输出:right
print
60
//
pFunc=(Func)*((int*)*((int*)(b)+2)+2);
61
//
pFunc();//段错误
62
63
delete
b;
64
return
0;
65
}
我们分三部分进行讲解:

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

根据代码中firstpart的输出情况,Left和Right的大小均为8,这个很好理解。int为4字节,加上虚指针的4字节即为8。Bottom的大小难道不应该是16字节吗?三个int总共12字节,另外还有一个虚指针4字节。错!这里Bottom对象中具有两个虚指针,因为它有两个父类,而两个父类均有虚函数。

根据Bottom对象中成员变量的地址输出情况,我们可以知道第一个虚指针位于对象的起始地址处,另外一个虚指针位于从Right继承而来的成员变量b之前。由此,我们可以得到对象的内存布局,如下图所示:



上面的图显示的是继承两个父类的内存布局情况,继承多个父类以此类推。

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

根据代码中secondpart的输出情况,我们可以看出主要虚函数表中包含Bottom对象的大部分虚函数,它们是:经过覆盖子类Left中的虚函数,Left没有被覆盖的虚函数,经过覆盖的Right中的虚函数,bottom独有的虚函数。但是请注意:bottom不包含Right独有的虚函数,它在次要虚函数表中。内部布局情况如下图所示:



主虚函数表中包含所有父类被覆盖的虚函数、第一个父类没有被覆盖的虚函数、以及子类独有的虚函数。需要注意的是:主虚函数表不包含除第一个父类外,其他父类没有被覆盖的虚函数。

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

根据代码中thirdpart部分的输出情况,我们可以看出次要虚函数表中包括被子类覆盖的Right父类中的虚函数,以及没有被子类覆盖的Right父类中的虚函数。需要注意的是代码中的红色部分,也许想象中是应该输出Bottom类有而Right类没有的print3虚函数,但是事实并非如此。该虚函数已经包含在主要虚函数表中了,就没有必要包含在次要虚函数表中。之所以要把虚函数表分成多部分,是为了让子类被不同的多个父类指针指向或引用时,能够正确的调整this指针位置,进行动态调用。因此,次要虚函数表就只需要包含相应的父类中被覆盖的虚函数以及未被覆盖的虚函数。内存布局,如下图所示:



总结下,在具有虚函数类的多继承时,子类包含一个主要虚函数表和一个或多个次要虚函数表。主虚函数表中包含所有父类被覆盖的虚函数、第一个父类没有被覆盖的虚函数、以及子类独有的虚函数。次要虚函数表仅包含对应的父类中被子类覆盖的虚函数以及没有被覆盖的虚函数,而不包含其他父类的虚函数以及子类特有的虚函数。

参考文献:

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