浅析GCC下C++多重继承 & 虚拟继承的对象内存布局
2012-07-18 12:48
316 查看
继承是C++作为OOD程序设计语言的三大特征(封装,继承,多态)之一,单一非多态继承是比较好理解的,本文主要讲解GCC环境下的多重继承和虚拟继承的对象内存布局。
一、多重继承
先看几个类的定义:
不难想象,Left和Right类的内存布局如下图所示:
我们如下进行验证:
从输出结果可以看出,父类指针top指向子类对象left和right的起始地址,与上述内存布局吻合。
在非虚拟多重继承的情况下,子类的内存布局是什么样子的呢?如下所示:
可以看出,Bottom类由于继承了Left和Right,而Left和Right又分别继承了Top。因此,Bottom包含了Top两次!
下面进行验证:
从输出结果可以看出,left指针和right指针分别指向了bottom对象中它们所处的位置:
由于bottom对象中存在两部分top对象,因此不能直接用top指针指向bottom对象,因为编译器不知道你的意图到底是指向left中的bottom部分,还是right中的bottom部分。需要进行转换才可以。如果需要通过bottom指针分别访问left和right中的top部分,可以如下:bottom->Left::a,bottom->Right::a。
好了,到这里讲完了非虚拟继承下的多重继承的内存布局情况,相信大家应该有一个比较清晰的认识了。最重要的一点是:多重继承时,父类共同继承的祖父类会在子类中有多份存在。
二、虚拟继承
平时讨论的最多的是虚函数,很少涉及到虚拟继承的情况。那么,虚拟继承到底是一个什么概念呢?
先来看一个例子:
对,你没有看错,类的大小输出不是48,而是412。虚拟继承时,编译器会在子类中安插上一个虚表指针。
从输出的对象成员地址来看,我们可以得到Child类的如下内存布局:
现在我们对多重继承的例子进行改造:
把Left和Right改成了虚拟继承Top。
从上面验证简单虚拟继承时,编译器安插虚表指针的例子,我们可以想象出此时Bottom类的对象内存布局如下:
对,你没有看错!虚拟继承时,子类只有父类共同继承的祖父类的一份存在。这其实也就是虚拟继承的最大用途。此时,Top,Left,Right和Bottom对象的大小分别为:4,12,12,24。
既然有虚表指针了,那么Bottom的虚表是什么样的呢?请看:
有了虚表,内存布局情况一目了然。下面我们进行验证:
根据输出结果,我们可以知道指针的指向情况:
由于引入了虚指针和虚表,left指针和right指针可以根据虚表提供的偏移量信息,轻松访问到Top::a。
到此为止,已经讨论清楚了多重继承和虚拟继承下的对象内存布局情况。总结下:非虚拟多重继承时,子类会有父类
共同继承祖父类的多份存在;虚拟继承时,子类会被安插一个虚拟指针;多重虚拟继承时,子类只有父类共同继承祖父类的一
份存在。通过父类的虚拟指针,可以正确地访问祖父类中的成员。
参考文献:
1.http://www.tbdata.org/archives/878
2.《深度探索C++对象模型》
一、多重继承
先看几个类的定义:
01 | class Top |
02 | { |
03 | public : |
04 | int a; |
05 | }; |
06 |
07 | class Left public Top |
08 | { |
09 | public : |
10 | int b; |
11 | }; |
12 |
13 | class Right public Top |
14 | { |
15 | public : |
16 | int c; |
17 | }; |
18 |
19 | class Bottom public Left, public Right |
20 | { |
21 | public : |
22 | int d; |
23 | }; |
我们如下进行验证:
1 | Left new Left(); |
2 | Top |
3 | cout '\t' << //输出:0x902c008 0x902c008 |
4 | Right new Right(); |
5 | top |
6 | cout '\t' << //输出:0x902c018 0x902c018 |
在非虚拟多重继承的情况下,子类的内存布局是什么样子的呢?如下所示:
可以看出,Bottom类由于继承了Left和Right,而Left和Right又分别继承了Top。因此,Bottom包含了Top两次!
下面进行验证:
1 | Bottom new Bottom(); |
1 | // |
1 | top |
1 | left |
2 | cout '\t' << '\t' << //输出:0x9930028 |
3 | top |
4 | right |
5 | cout '\t' << '\t' << //输出:0x9930028 |
由于bottom对象中存在两部分top对象,因此不能直接用top指针指向bottom对象,因为编译器不知道你的意图到底是指向left中的bottom部分,还是right中的bottom部分。需要进行转换才可以。如果需要通过bottom指针分别访问left和right中的top部分,可以如下:bottom->Left::a,bottom->Right::a。
好了,到这里讲完了非虚拟继承下的多重继承的内存布局情况,相信大家应该有一个比较清晰的认识了。最重要的一点是:多重继承时,父类共同继承的祖父类会在子类中有多份存在。
二、虚拟继承
平时讨论的最多的是虚函数,很少涉及到虚拟继承的情况。那么,虚拟继承到底是一个什么概念呢?
先来看一个例子:
01 | #include <iostream> |
02 | using namespace std; |
03 |
04 | class Father |
05 | { |
06 | public : |
07 | int a; |
08 | }; |
09 |
10 | class Child virtual public Father |
11 | { |
12 | public : |
13 | int b; |
14 | }; |
15 |
16 | int main() |
17 | { |
18 | cout sizeof (Father) '\t' << sizeof (Child) //输出:4 12 |
19 | Child child; |
20 | cout '\t' << '\t' << //输出:0xbfc08124 |
21 | return 0; |
22 | } |
从输出的对象成员地址来看,我们可以得到Child类的如下内存布局:
现在我们对多重继承的例子进行改造:
01 | class Top |
02 | { |
03 | public : |
04 | int a; |
05 | }; |
06 |
07 | class Left virtual public Top |
08 | { |
09 | public : |
10 | int b; |
11 | }; |
12 |
13 | class Right virtual public Top |
14 | { |
15 | public : |
16 | int c; |
17 | }; |
18 |
19 | class Bottom public Left, public Right |
20 | { |
21 | public : |
22 | int d; |
23 | }; |
从上面验证简单虚拟继承时,编译器安插虚表指针的例子,我们可以想象出此时Bottom类的对象内存布局如下:
对,你没有看错!虚拟继承时,子类只有父类共同继承的祖父类的一份存在。这其实也就是虚拟继承的最大用途。此时,Top,Left,Right和Bottom对象的大小分别为:4,12,12,24。
既然有虚表指针了,那么Bottom的虚表是什么样的呢?请看:
有了虚表,内存布局情况一目了然。下面我们进行验证:
1 | Bottom new Bottom(); |
2 | top |
3 | cout '\t' << //输出:0x9fa5028 0x9fa503c |
4 | Left |
5 | cout '\t' << //输出:0x9fa5028 0x9fa5028 |
6 | Right |
7 | cout '\t' << //输出:0x9fa5028 0x9fa5030 |
由于引入了虚指针和虚表,left指针和right指针可以根据虚表提供的偏移量信息,轻松访问到Top::a。
到此为止,已经讨论清楚了多重继承和虚拟继承下的对象内存布局情况。总结下:非虚拟多重继承时,子类会有父类
共同继承祖父类的多份存在;虚拟继承时,子类会被安插一个虚拟指针;多重虚拟继承时,子类只有父类共同继承祖父类的一
份存在。通过父类的虚拟指针,可以正确地访问祖父类中的成员。
参考文献:
1.
2.《深度探索C++对象模型》
相关文章推荐
- 浅析GCC下C++多重继承 & 虚拟继承的对象内存布局 - 问笑
- 浅析GCC下C++多重继承 & 虚拟继承的对象内存布局
- 浅析GCC下C++多重继承 & 虚拟继承的对象内存布局
- C++对象内存布局--⑦VS编译器--虚拟继承多个基类
- 类对象内存布局,虚函数,虚拟继承和多重继承的实现
- 面向对象--多继承&派生类对象内存布局分析&各基类指针所指向的位置分析(解决面试宝典第四版P147问题)
- 面向对象--多继承&派生类对象内存布局分析&各基类指针所指向的位置分析
- C++对象内存布局--⑩GCC编译器--虚拟继承--菱形继承
- C++对象内存布局--⑧GCC编译器--虚拟继承多个基类
- C++对象内存布局--⑨VS编译器--虚拟继承--菱形继承
- C++对象内存布局--⑩GCC编译器--虚拟继承--菱形继承
- 面向对象--多继承&派生类对象内存布局分析&各基类指针所指向的位置分析
- C++ 对象的内存布局(多重虚拟继承)
- c++虚继承对象的内存布局
- 多重虚继承下的对象内存布局
- C++虚继承中的对象内存布局
- 多重继承和虚拟继承的内存布局
- C++ 对象的内存布局(重复继承)
- C++虚拟继承__对象内存的分布_虚继承会多余分配虚表v-tab的指
- C++-对象继承中的内存布局