C++虚拟继承中的对象模型

    最近,从师兄那里听到一道据说是某国内知名IT公司的面试题,有关C++虚拟继承的。

  1. #include <iostream>
  2. using namespace std;
  3. class T {
  4. //public:
  5. //  char ch;
  6. //  static  char ch;
  7. };
  8. class A : virtual public T {
  9. }; 
  10. class B : virtual public T {
  11. }; 
  12. class C : public A, public B {
  13. }; 
  14. class D : public A, virtual public B {
  15. }; 
  16. class E : virtual public A, virtual public B {
  17. }; 
  18. int main()
  19. {
  20.     cout << sizeof(T) << endl;
  21.     cout << sizeof(A) << endl;
  22.     cout << sizeof(B) << endl;
  23.     cout << sizeof(C) << endl;
  24.     cout << sizeof(D) << endl;
  25.     cout << sizeof(E) << endl;
  26.     return 0;
  27. }
  28. //问输出结果?
  29. /*
  30. vc6.0
  31. 1
  32. 4
  33. 4
  34. 8
  35. 8
  36. 12
  37. devc++5.0, 32位,内核是gcc
  38. 1
  39. 4
  40. 4
  41. 8
  42. 8
  43. 8
  44. g++ 4.1, 64位
  45. 1
  46. 8
  47. 8
  48. 16
  49. 16
  50. 16
  51. */
  52. /*
  53. C++对象模型里面有提到的另一种情况(即没对empty virtual base class做优化),不知道是用那种C++编译器,其结果如下:
  54. sizeof(T) = 1
  55. sizeof(A) = 8
  56. sizeof(B) = 8
  57. sizeof(C) = 12
  58. */

    

    之前只是了解虚拟继承是为C++多继承时,同一基类在派生层次中多次出现,引起的存储空间浪费,和二义性,而提出来的解决方案。而对具体的对象数据布局,就不是很清楚了,在VC++6.0上跑了一下这个程序,照着结果理解了半天都没找到能够同时把C(8),D(8),E(12)三个都解释得通的模型。

 

    在网站找来一些资料,也是众说纷纭。最后下了JJHOU译的《深入探索C++对象模型》看了第3 Data 语义学部分,讲得较为详细。对其中主要部分解释总结如下:

 

1.       语言本身造成的额外负担,即虚拟继承中子类中必须保存指向virtual base class subobject的指针或一个相关表格的偏移量。指针的大小跟机器有关;

 

2.       编译器对于特殊情况所提供的最佳化处理,virtual base class subobject会放在derived class的固定(不变动)部分尾端,即上述T1byte大小会出现在A,B上。而有些编译器会对虚拟继承中的空基类提供优化处理,在这种策略下,一个empty virtual base class 就被视为derived class object最开头的一部分,而它并没有花费任何额外的空间,如VC++6.0里sizeof(A)=4;

 

3.       Alignment的限制,如果不考虑对empty virtual base class进行优化,AB大小截止到目前为5bytes。在大部分机器上,结构体大小受alignment限制,以使它们能够更有效率地在内存中被存取,上面测试的结构所使用的机器均为4bytes对齐,即会出现上述最后一种情况sizeof(A)=8。关于Alignment自己想了一个的例子如下:

  1. class S {   
  2. private :
  3.     char ach;
  4.     int i;
  5.     char bch;
  6. };//sizeof(S)=12

    嘿,总之C++的对象布局,除了语言本身外,还要考虑机器,编译器的因素。这些拿来当笔试面试的题目,还真不好答。

    至于sizeof(E)的大小vc6.0devc++5.0的不同还是不清楚晕,应该也是编译器处理策略不同引起的。

 

    sizeof(T)1:根据对象唯一性原则,编译器隐晦插入一个字节,以使类的不同实例,在内存中拥有唯一的地址。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值