首先看一个例子:
1 #include <iostream> 2 using namespace std; 3 4 class A{}; 5 6 class B 7 { 8 int b; 9 char c; 10 }; 11 12 class C 13 { 14 int c1; 15 static int c2; 16 }; 17 int C::c2 = 1; 18 19 class D:public C,public B{ 20 int d; 21 }; 22 int main() 23 { 24 cout<<"sizeof(A)="<<sizeof(A)<<endl; 25 cout<<"sizeof(B)="<<sizeof(B)<<endl; 26 cout<<"sizeof(C)="<<sizeof(C)<<endl; 27 cout<<"sizeof(D)="<<sizeof(D)<<endl; 28 29 return 0; 30 }
运行结果为:
sizeof(A)=1
sizeof(B)=8
sizeof(C)=4
sizeof(D)=16
对于类A来说,虽然A是一个空类,但为了便于空类进行实例化,编译器往往会给它分配一个字节,这样A实例化后便在内存中有了一个独一无二的地址.对于类B,B的大小应为sizeof(int)+sizeof(char)=5,但是考虑内存对齐,B的大小应为8.对于类C,类的静态成员变量被放在全局区,和类的普通成员并没有放在一块。类的静态成员被声明后就已存在,而非静态成员只有类被实例化后才存在。所以C的大小为sizeof(int)=4。D的大小为B+C的大小+自身数据成员的大小,一共为16.
==========================分割线在这里====================================
下面讨论含有虚函数的类的大小:
1 #include <iostream> 2 using namespace std; 3 4 class A 5 { 6 public: 7 void virtual aa(){}; 8 }; 9 10 class B:public A 11 { 12 void virtual bb(){}; 13 }; 14 15 class C:virtual A 16 { 17 public: 18 void virtual aa(){}; 19 void cc(){}; 20 }; 21 22 class D:virtual A 23 { 24 public: 25 void virtual dd(){}; 26 }; 27 28 int main() 29 { 30 cout<<"sizeof(A)="<<sizeof(A)<<endl; 31 cout<<"sizeof(B)="<<sizeof(B)<<endl; 32 cout<<"sizeof(C)="<<sizeof(C)<<endl; 33 cout<<"sizeof(D)="<<sizeof(D)<<endl; 34 35 return 0; 36 }
运行结果为:
sizeof(A)=4
sizeof(B)=4
sizeof(C)=8
sizeof(D)=12
对于class A,它含有一个虚函数,编译器会为虚函数生成一张虚函数表,来记录对应的函数地址,为此,在class A的内存地址中要有一个vfptr_A指针指向这个虚表,所以class A的大小为指针大小,即4.(注意,无论类中有多少个虚函数,它们的大小都是4,因为内存中只需要保存这个指针即可)。
对于class B,它是public继承A,虽然它也有一个虚函数,但是从结果看,B应该和A都在B的vtable(虚表中),所以class B的大小为4.
对于class C,它是vitual 继承A,所以要有一个指向父类A的指针,占有4字节大小aa()是继承自class A的虚函数,从结果来看,它没有在内存中占有空间,所以C的大小为sizeof(A)+4=8.
对于class D,它是虚继承class A,同上,要有一个指向父类A的指针,同时,class D中有虚函数,所以要有一个指向虚表的指针,所以sizeof(D)=sizeof(A)+4+4=12