2013亚马逊面试题--虚继承的内存模型分析

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
[cpp] view plaincopyprint?
1. #include <iostream> 2. using namespace std; 3. 本文由西安白癜风医院 http://www.jypenglai.com/ 收集,转载请注明出处
本文由西安白癜风医院 http://www.jypenglai.com/ 收集,转载请注明出处 4. class Base 5. { 6. public: 7. 8. 9. }; 10. 11. class Derived : public Base 12. { 13. public: 14. 16. 17. 18. }; 19. 20. int main() 21. { 22. } virtual void fcn2() {}; int d; void fcn3() { } 15. private: int a; virtual void fcn() {};
从这个内存布局就可以看出来 class A、class A1 和 ClassB 的大小,本身 class A 的大小应该是 1bytes 的内存定位大小加上虚函数指针 4bytes 因为有了虚函数指针后 1bytes 的占位就可以取消了。所以 A 的大小就是 4bytes,同理 Class A1。对于 Class B 它主要是 从 class A 和 class A1(虚继承)而来,所以 B 里面包含有一个 A 和 A1 同时因为是需继承 所以就有一个指向虚基类(A1)的 vbptr 指针。这里为了方便我做个图直观一点:
//
输出结果是:
在命令行中输入:
[cpp] view plaincopyprint?
本文由西安白癜风医院 http://www.jypenglai.com/ 收集,转载请注明出处
本文由西安白癜风医院 http://www.jypenglai.com/ 收集,转载请注明出处 1. cl test.cpp /d1reportSingleClassLayoutB
查看 Derived 这个类的对象在内存中的布局,那么就可以用下面的命令行:
[cpp] view plaincopyprint?
1. cl Test.cpp /d1reportSingleClassLayoutDerived
结果显示如下:
本文由西安白癜风医院 http://www.jypenglai.com/ 收集,转载请注明出处
vs2010 下的 cl 命令
微软的 VS2010 提供了一个新的选项,给用户显示 C++对象在内存中的布局。这个选项 就是:
[cpp] view plaincopyprint?
1. /d1reportSingleClassLayout
具体使用方法如下,在写好相应的 cpp 文件之后,需要启动 VS2010 的命令行工具“Visual Studio 2010Command Prompt”,切换到 cpp 文件所在目录之后,输入如下的命令:
本文由西安白癜风医院 http://www.jypenglai.com/ 收集,转载请注明出处
可以看到 class Derived 的对象的内存布局, 在派生类对象的开始包含了基类 Base 的 对象, 其中有一个虚表指针, 指向的就是下面的 Derived::$vftable@( virtual function table ) , 表中包含了 Derived 类中所有的虚函数。
本文由西安白癜风医院 http://www.jypenglai.com/ 收集,转载请注明出处
本文由西安白癜风医院 http://www.jypenglai.com/ 收集,转载请注明出处
该是: vbtable 指针( 4bytes) +固定局部(a, b 工 8bytes)+ C 的 4bytes(这有点不好明 白,不过下面我还有例子,加深理解)。 代码三:
从 vs2010 的内存来看的确也是分配了,通过前面的 vbtable 的偏移来看对象的大 小就是 16bytes( a 是 class A 的首地址, b 是 classB 的首地址)。有人会问为什么不是 20bytes?上面的内存分配偏移是 16 就说明有 20bytes。偏移 16,刚好在变量 b 的下面分 配 4bytes 的 C(这说的不准确,不过好明白)这样偏移是 16 的地方就是 D , vbtable 现在 可以正常定位,Class D 为空,就没有必要再分配 4bytes 的空间,所以 sizeof E 的大小应
1. E::$vbtable@: 2. 1> 3. 1> 0 1 | 0 | 4 (Ed(E+0)A) 本文由西安白癜风医院 http://www.jypenglai.com/ 收集,转载请注明出处
本文由西安白癜风医院 http://www.jypenglai.com/ 收集,转载请注明出处 4. 1> 5. 1> 6. 1> 2 3 4 | 8 (Ed(E+0)B) | 12 (Ed(E+0)C) | 16 (Ed(E+0)D)
//
上面代码二输出的结果:
这回感觉还是很奇怪吧,看看内存布局吧。
本文由西安白癜风医院 http://www.jypenglai.com/ 收集,转载请注明出处
内存模型
在这一小节里面我主要从他面试的几个题目中来谈谈虚继承的内存模型。 代码一:
[cpp] view plaincopyprint?
1. class A 2. { 3. 4. 5. 6. }; 7. class A1 8. { 9. 10. 11. 12. }; 13. 14. class B : public A , virtual public A1 15. { 16. }; 17. void main() 18. { 19. 20. 21. 22. } cout<<"sizeof A: "<<sizeof(A)<<endl; cout<<"sizeof A1: "<<sizeof(A1)<<endl; cout<<"sizeof B: "<<sizeof(B)<<endl; virtual void a() { } virtual void a() { }
一般都是把 vbtable 放在对象的前面,所以 vbtable(virtual base class table) 与对象首地址的偏移量一般就是中间隔着 vbtable, 这个地方的 4 表示 E 的 vbtable 与虚基 类 A 首地址的偏移量,同理,8,12,16 这个就不用我说了。既然这都给出了 vbtable 域虚 基类的地址偏移量了,说明在 E 对象的内存中还是存在分配的空间。
[cpp] view plaincopyprint?
1. class A 2. { 3. }; 4. class B 5. { 6. 7. }; 8. 9. class C 10. { 11. }; 12. class D 13. { 14. }; 15. class E: public virtual A , public virtual B , public virtual C , public vir tual D 16. { 17. }; 18. void main() 19. { 20. 21. 22. 23. 24. 25. } cout<<"sizeof A: "<<sizeof(A)<<endl; cout<<"sizeof B: "<<sizeof(B)<<endl; cout<<"sizeof C: "<<sizeof(C)<<endl; cout<<"sizeof D: "<<sizeof(D)<<endl; cout<<"sizeof E: "<<sizeof(E)<<endl; int b;
//
Class 如果内含一个或多个 virtual base class subobjects, 将被分割为两部分:一个 不变局部和一个共享局部.不变局部中的数据,不管后继如何衍化,总是拥有固定的 offset(从 object 的开头算起),所以这一部分数据可以被直接存取。至于共享局部,所表 现的就是 virtual base class subobject。这一部分的数据,其位置会因为每次的派生操作 而有变化, 所以它们只可以被间接存取。 各家编译器实现技术之间的差异就在于间接存取的 方法不同。 一般的布局策略是先安排好 derived class 的不变部分, 然后再建立其共享部分. 然而, 这中间存在着一个问题:如何能够存取 Class 的共享部分呢?我这就从微软的编译器来 看它的内存布局。 上面代码二输出的结果:

虚继承和虚基类 vs2010 下的 cl 命令 内存模型
虚继承和虚基类
虚继承:在继承定义中包含了 virtual 关键字的继承关系; 虚基类:在虚继承体系中的通过 virtual 继承而来的基类,需要注意的是:class CSubClass : public virtual CBase {}; 其中 CBase 称之为 CSubClass 的虚基类,而不是说 CBase 就是个虚基类,因为 CBase 还可以不不是虚继承体系中的基类。
如前面黑色字体标注一样,因为 classE 是多重虚继承,所以在内存中的布局是分 为固定局部和共享局部, 固定局部的大小就 int a, b 所以是 8 bytes。 我的上一篇博文 (VC++ 对象布局的奥秘:虚函数、多继承、虚拟继承)对这个内存某型有个大概的讲解,在这就不 多言了。
[cpp] view plaincopyprint?
本文由西安白癜风医院 http://www.jypenglai.com/ 收集,转载请注明出处
2013 亚马逊面试题--虚继承的内存模型分析
前两天逛论坛的时候,看到一个有关虚继承中类的大小(亚马逊二面的面试题)帖子, 看了下还真不会,觉得慢慢研究下。大概搞明白为什么了,将自己的一点结果跟大家分享下 吧,欢迎拍板。(我的上一篇博客也虚继承有相关解释) 这里就先从以下几个ห้องสมุดไป่ตู้进行说明吧:
本文由西安白癜风医院 http://www.jypenglai.com/ 收集,转载请注明出处
本文由西安白癜风医院 http://www.jypenglai.com/ 收集,转载请注明出处
class E 的大小是不是有点怪,在命令行中输入:
[cpp] view plaincopyprint?
1. cl test.cpp /d1reportSingleClassLayoutE
[cpp] view plaincopyprint?
1. cl [filename].cpp /d1reportSingleClassLayout[className]
cl 当然就是 MS 的编译器; [filename].cpp 就是你所想要查看的 class 所在的 cpp 文件 (class 定义在头文件也没关系,还是只要编译 cpp 文件即可) ;而你需要在最后加上 [className], 也就是你需要查看的 class 的类名。 【举例】test.cpp 文件代码如下:
所以说 class B 的大小是 12bytes 代码二:
[cpp] view plaincopyprint?
本文由西安白癜风医院 http://www.jypenglai.com/ 收集,转载请注明出处
本文由西安白癜风医院 http://www.jypenglai.com/ 收集,转载请注明出处 1. class A 2. { 3. 4. }; 5. class B 6. { 7. 8. }; 9. 10. class C 11. { 12. }; 13. class D 14. { 15. }; 16. class E: public virtual A , public virtual B , public virtual C , public vir tual D 17. { 18. }; 19. void main() 20. { 21. 22. } cout<<"sizeof E: "<<sizeof(E)<<endl; int b; int a;
相关文档
最新文档