跟我一起学习C++虚函数--第四篇
2012-07-18 12:51
85 查看
在前一篇,我们讨论了在多继承情况下,具有虚函数的类的内存布局情况。本篇将进一步探索在多重继承,即具有重复继承的情况下的内存布局情况。在阅读本篇和下一篇之前,建议先阅读本博客另一篇博文《浅析GCC下C++多重继承
&虚拟继承的对象内存布局》。
先说一点题外话,细心的读者可能会发现,我们在探索不同情况下类的内存布局时,总是先通过查看类的大小以及其中各个成员变量的地址来进行分析,然后再具体定位某一位置的值。从最原始的内存中的对象分布,我们可以获得最深入最有效的理解。
OK,请看例子:
对于上面的例子,我们分为三部分进行讲解。
第一部分:多重继承情况下,对象本身(除虚函数表外)的内存布局。
从代码中firstpart的输出情况来看,Top、Left和Right的大小很容易理解,至于Bottom类的大小,如果你看过参考文献一,那么也很容易理解。Bottom类包含了两次Top类中的a成员变量,因此总共有5个int成员变量,为20字节。再加上两个虚指针,即为28字节。
从输出的Bottom对象中成员变量地址情况,我们可以用如下图来表示内存布局:
简单地说,多重继承时,子类会有多个祖父类的存在。
第二部分:多重继承情况下,主要虚函数表的内存布局。
从代码的secondpart的输出情况来看,我们可以用下图来表示主要虚函数表的内存布局:
第三部分:多重继承情况下,次要虚函数表的内存布局。
从代码的thirdpart的输出情况来看,我们可以用下图来表示次要虚函数表的内存布局:
对比前一篇多继承情况下类的内存布局,我们可以发现:在多重继承情况下,不仅祖父类的成员变量在子类中会有多份存在,祖父类的虚函数同样会在子类的虚函数表中有多份存在,分别位于主要虚函数表和次要虚函数表中。
参考文献:
1.《浅析GCC下C++多重继承&虚拟继承的对象内存布局》
2.《深度探索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) |
45 | //输出:8 |
46 | Bottom new Bottom(); |
47 | cout " " << " " << " " << " " << " " << |
48 | //输出:0x8c0f008 |
49 |
50 | /*second part*/ |
51 | typedef void (*Func)( void ); |
52 | Func pFunc; |
53 | pFunc int *)*( int *)(b)); |
54 | pFunc(); //输出:top x |
55 | pFunc int *)*( int *)(b)+1); |
56 | pFunc(); //输出:top print |
57 | pFunc int *)*( int *)(b)+2); |
58 | pFunc(); //输出:bottom y |
59 | pFunc int *)*( int *)(b)+3); |
60 | pFunc(); //输出:left print |
61 | pFunc int *)*( int *)(b)+4); |
62 | pFunc(); //输出:bottom z |
63 | pFunc int *)*( int *)(b)+5); |
64 | pFunc(); //输出:bottom print |
65 | //pFunc |
66 | //pFunc();//段错误 |
67 |
68 | /*third part*/ |
69 | pFunc int *)*(( int *)(b)+3)); |
70 | pFunc(); //输出:top x |
71 | pFunc int *)*(( int *)(b)+3)+1); |
72 | pFunc(); //输出:top print |
73 | pFunc int *)*(( int *)(b)+3)+2); |
74 | pFunc(); //输出:bottom z |
75 | pFunc int *)*(( int *)(b)+3)+3); |
76 | pFunc(); //输出:right print |
77 | //pFunc |
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.《
2.《深度探索C++对象模型》
相关文章推荐
- 跟我一起学习C++虚函数--第四篇
- 跟我一起学习C++虚函数--第四篇
- 跟我一起学习C++虚函数--第一篇
- 跟我一起学习C++虚函数--第五篇
- 跟我一起学习C++虚函数--第二篇
- 跟我一起学习C++虚函数--第一篇
- 跟我一起学习C++虚函数--第三篇
- 跟我一起学习C++虚函数--第二篇
- 跟我一起学习C++虚函数--第一篇
- 跟我一起学习C++虚函数--第五篇
- 跟我一起学习C++虚函数--第二篇
- 跟我一起学习C++虚函数--第三篇
- 跟我一起学习C++虚函数--第三篇
- 跟我一起学习C++虚函数--第五篇
- C++ 学习笔记(15)面向对象程序设计(类、继承、虚函数、抽象类、using命令、容器与继承)
- C++学习笔记(11)——虚函数的特性
- c++学习笔记——虚函数(virtual function)
- C++学习笔记――多态性和虚函数
- 开始学习C++——第二篇 虚函数的作用(摘自onlinewan 百度知道)
- C++ 虚函数内存布局学习笔记