C++类的大小在GCC和VC上的区别

本文探讨了C++中类的内存布局,包括空类、含有虚函数的类、多继承派生类在GCC和VC编译器下的大小差异。详细分析了虚函数表指针(vptr)和字节对齐规则如何影响类的大小。在虚继承的情况下,GCC和VC编译器的不同处理方式也进行了比较。通过对实例的分析,揭示了不同编译器在内存管理和多继承处理上的策略差异。
摘要由CSDN通过智能技术生成

#include<iostream>

using namespace std;

class A    

{    

};   

class B    

    char ch;    

    virtual void func0()  {  }  

};  

class C   

    char ch1; 

    char ch2; 

    virtual void func()  {  }   

    virtual void func1()  {  }  

}; 

class D: public A, public 

{    

    int d;    

    virtual void func()  {  }  

    virtual void func1()  {  } 

};    

class E: public B, public 

{    

    int e;    

    virtual void func0()  {  }  

    virtual void func1()  {  } 

}; 

int main(void

    cout<<"A="<<sizeof(A)<<endl;    //result=1 

    cout<<"B="<<sizeof(B)<<endl;    //result=16     

    cout<<"C="<<sizeof(C)<<endl;    //result=16 

    cout<<"D="<<sizeof(D)<<endl;    //result=16 

    cout<<"E="<<sizeof(E)<<endl;    //result=32 

    return 0; 

}

在GCC编译器下进行编译,有如下结果

结果分析: 

  1.A为空类,所以大小为1 ;

  2.B的大小为char数据成员大小+vptr指针大小。由于字节对齐,大小为8+8=16 ;

  3.C的大小为两个char数据成员大小+vptr指针大小。由于字节对齐,大小为8+8=16 ;

  4.D为多继承派生类,由于D有数据成员,所以继承空类A时,空类A的大小1字节并没有计入当中,D继承C,此情况D只需要一个vptr指针,所以大小为数据成员加一个指针大小。由于字节对齐,大小为8+8=16 ;

  5.E为多继承派生类,此情况为我们上面所讲的多重继承,含虚函数覆盖的情况。此时大小计算为数据成员的大小+2个基类虚函数表指针大小 ,考虑字节对齐,继承顺序B在先,B(8 + 1),然后是C(8+1+1),由于字节对齐,B得与C中最大值对齐,因此B+7变成16,再+C(10),得26,最后+E的其它成员+1,因为要整体对于最大值(8)对齐,因此补齐得32。

在vc编译器下进行编译,有如下结果

 

结果分析: 

  4.D为多继承派生类,由于D有数据成员,所以继承空类A时,空类A的大小1字节并没有计入当中,D继承C,此情况D只需要一个vptr指针,所以大小为数据成员加一个指针大小。这里和GCC最大的区别就是D和C不能合并在一起单独进行内存对齐的计算,需要分开进行计算,所以由于字节对齐,大小为8+1+1+6+4+4=24 ;

  5.E为多继承派生类,含虚函数覆盖的情况。此时大小计算为数据成员的大小+2个基类虚函数表指针大小 ,同样犹豫每个类需要单独进行内存对齐的计算,所以有8+1+7+8+1+1+6+4+4=40

二.虚继承的情况

  对虚继承层次的对象的内存布局,在不同编译器实现有所区别。 

  在这里,首先要说的是在gcc编译器下,虚继承大小的计算。它在gcc下实现比较简单,不管是否虚继承,GCC都是将虚表指针在整个继承关系中共享的,不共享的是指向虚基类的指针。

class A {

   int a;

   virtual void myfuncA(){}

};

class B:virtual public A{

    virtual void myfunB(){}

};

class C:virtual public A{

    virtual void myfunC(){}

};

class D:public B,public C{

    virtual void myfunD(){}

};

sizeof(A)=16,sizeof(B)=24,sizeof(C)=24,sizeof(D)=48;

  A的大小为int大小加上虚表指针大小;

  B,C中由于是虚继承,因此大小为int大小加指向虚基类的指针的大小。B,C虽然加入了自己的虚函数,但是虚表指针是和基类共享的,因此不会有自己的虚表指针,他们两个共用虚基类A的虚表指针。D由于B,C都是虚继承,其大小等于B+C)。

在VC编译器下,有如下结果图:

 在VC编译器下,由于涉及到虚函数表和虚基表,会同时增加一个(多重虚继承下对应多个)vfPtr指针指向虚函数表vfTable和一个vbPtr指针指向虚基表vbTable,这两者所占的空间大小为:16(或16乘以多继承时父类的个数),vc下虚表指针不会共享;

sizeof(C)=32,其中内存分布如下图所示:

  1. class C size(32):    
  2.      +---    
  3.  | | {vfptr}    
  4.  | | {vbptr}       
  5.  | | {vptr}  
  6.       | +--- 
  7.      | +--- (virtual base class A)    
  8.  | a   

sizeof(D)=48,其中内存分布如下图所示:

  1. class D size(48):    
  2.      +---    
  3.      | +--- (base class B)    
  4.  | | {vfptr}    
  5.  | | {vbptr}        
  6.      | +---    
  7.      | +--- (base class C)    
  8.  | | {vfptr}    
  9.  | | {vbptr}    
  10.     | +---    
  11.   | |{vptr}   
  12.     +---    
  13.     +--- (virtual base A)  
  14.  | d   
  15.     +---  
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值