关于类或者结构体中的内存布局

结构体或者类的内存布局一般一局两个规则

1)成员变量从内存地址0开始,每个变量都认为是按照自己的类型大小来分配内存,所以每个变量的起始地址都应该是自身类型的整数倍

2)这个内存大小应该是最大的成员变量类型的整数倍

特殊情况:

1:如果类没有任何成员变量则大小为1

2:类的static成员变量不在类对象内,他们有唯一的实体

3:如果类或者结构体中含有其他类或者结构体,那么内存大小和变量以及类对象的排序有关

例如

 1 class A
 2    {
 3         int a;
 4         char b;
 5         double c;
 6    };
 7 class B
 8    {
 9        int m;
10       A a;
11    };

其中A的大小为16个字节,而计算B的时候,a的起始地址是按照A中最大字节的类型也就是double类型的整数倍。所以a的起始位置从8开始,,最后的字节数为两个类中最大类型的整数倍也就是double的整数类。

5:如果结构体或者类中又数组成员变量,则按照数组类型的一个个进行内存分配

4:如果类中有虚函数,则计算时需要增加一个虚函数指针。

5:如果类继承了多个基类,每个基类都有虚函数,则有多少个基类就有多少个虚函数指针,并且继承基类的成员变量

6:对于虚继承,VC和GCC编译器对内存分布有一些不同

GCC编译器:对于是否是虚继承,整个继承体系虚函数指针都是共享的,而虚基类指针不是共享的

VC编译器:对于是否虚继承,整个继承体系不共享的虚函数指针,每个子类维护自己的虚函数表,非虚继承则共享虚函数指针。不管是否虚继承,虚基类指针不共享

GCC编译器:

它实现比较简单,不管是否虚继承,GCC都是将虚表指针在整个继承关系中共享的,不共享的是指向虚基类的指针。

 

如下例(取自程序员面试宝典(三)P130)

详解:

 

A中sizeof(int)+sizeof(虚表指针)=8 。

B,C中

如果不是虚继承,下列代码 (I)

sizeof(B)= sizeof(A)+B中元素大小 - B中虚函数表指针大小(4)【因为虚表指针在整个继承关系中是共享的,只需存在A中的虚表指针】= 12;

sizeof(C)同理B;最终为16;

如果是虚继承,下列代码 (II)

相对于非虚继承,sizeof(B)中多了一个虚函数指针(4Byte),而且C中的虚继承指针是不与B共享的。即虚继承指针不共享;

 

VC编译器:

例子相同:

 

VC对虚表指针的处理比GCC复杂,它根据是否为虚继承来判断是否在继承关系中共享虚表指针,而对指向虚基类的指针和GCC一样是不共享的

如果为虚继承,则他的继承关系中不会共享虚函数表,而是每个子类维护自己的虚函数表,但是如果不是虚继承,他的继承关系还是共享虚函数表的;

 

A中sizeof(int)+sizeof(虚表指针)=8 。

B,C中

如果不是虚继承,下列代码 (I) 

sizeof(B)= sizeof(A)+B中元素大小- B中虚函数表指针大小(4)【因为虚表指针在整个继承关系中是共享的,只需存在A中的虚表指针】= 12;

sizeof(C)同理B;最终为16;

如果是虚继承,下列代码 (II)

sizeof(B)= sizeof(A)+B中元素大小(包括sizeof(char[3](字节对齐4)+sizeof(虚指针))+ sizeof(虚基类指针)= 20;

C同B分析;

 

代码(I)

 


 
  1. #include <iostream>  
  2. #include <stdio.h>  
  3. #include <cstdlib>  
  4. #include <memory.h>  
  5. #include <assert.h>  
  6.   
  7.   
  8. using namespace std;  
  9.   
  10. class A  
  11. {  
  12.     char k[3];  
  13.     public:  
  14.         virtual void aa(){};  
  15. };  
  16. class B : public  A  
  17. {  
  18.   
  19.     char j[3];  
  20.     public:  
  21.         virtual void bb(){};  
  22. };  
  23. class C : public  B  
  24. {  
  25.     char i[3];  
  26.     public:  
  27.         virtual void cc(){};  
  28.   
  29. };  
  30.   
  31. int main(int argc , char *argv[])  
  32. {  
  33.     cout<<"sizeof(A):"<<sizeof(A)<<endl;  
  34.     cout<<"sizeof(B):"<<sizeof(B)<<endl;  
  35.     cout<<"sizeof(C):"<<sizeof(C)<<endl;  
  36.   
  37.     return 0;  
  38. }  

 

 

GCC编译结果:

sizeof(A):8
sizeof(B):12
sizeof(C):16


Process returned 0 (0x0)   execution time : 3.330 s
Press any key to continue.

 

VC编译结果:

sizeof(A):8
sizeof(B):12
sizeof(C):16


Process returned 0 (0x0)   execution time : 0.487 s
Press any key to continue.

 

 

代码(II)

[cpp] view plaincopy
 
  1. #include <iostream>  
  2. #include <stdio.h>  
  3. #include <cstdlib>  
  4. #include <memory.h>  
  5. #include <assert.h>  
  6.   
  7.   
  8. using namespace std;  
  9.   
  10. class A  
  11. {  
  12.     char k[3];  
  13.     public:  
  14.         virtual void aa(){};  
  15. };  
  16. class B : public virtual A  
  17. {  
  18.   
  19.     char j[3];  
  20.     public:  
  21.         virtual void bb(){};  
  22. };  
  23. class C : public virtual B  
  24. {  
  25.     char i[3];  
  26.     public:  
  27.         virtual void cc(){};  
  28.   
  29. };  
  30.   
  31. int main(int argc , char *argv[])  
  32. {  
  33.     cout<<"sizeof(A):"<<sizeof(A)<<endl;  
  34.     cout<<"sizeof(B):"<<sizeof(B)<<endl;  
  35.     cout<<"sizeof(C):"<<sizeof(C)<<endl;  
  36.   
  37.     return 0;  
  38. }  

 

GCC编译器输出结果:

sizeof(A):8
sizeof(B):16
sizeof(C):24


Process returned 0 (0x0)   execution time : 0.501 s
Press any key to continue.

 

VC编译器输出结果:

 

sizeof(A):8
sizeof(B):20
sizeof(C):32

 

posted on 2015-06-08 15:24  菜鸟基地  阅读(206)  评论(0)    收藏  举报

导航