涉及到c++中求类大小时需要特别注意一下几点

1.为类的非静态成员数据的类型大小之和.

2.有编译器额外加入的成员变量的大小,用来支持语言的某些特性(如:指向虚函数的指针、虚继承、多重继承).

3.为了优化存取效率,进行的边缘调整.

4.  与类中的构造函数,析构函数以及其他的成员函数无关.

5.  私有继承,会去继承之前的私有成员变量么? 会...在内存中仍然分配相应的空间,只是在子类中是不可见的!

6.  在做多层次的继承类大小时某个子类的类大小总是等于父类的大小加上子类中数据成员和是否有虚函数,是否是虚继承等因素来决定。


  • 空类大小为1

首先:我们要知道什么是类的实例化,所谓类的实例化就是在内存中分配一块地址.


那我们先看看一个例子:

#include<iostream.h>

class a {};
class b{};
class c:public a{
virtual void fun()=0;
};
class d:public b,public c{};
int main()
{
cout<<"sizeof(a)"<<sizeof(a)<<endl;
cout<<"sizeof(b)"<<sizeof(b)<<endl;
cout<<"sizeof(c)"<<sizeof(c)<<endl;
cout<<"sizeof(d)"<<sizeof(d)<<endl;
return 0;}

程序执行的输出结果为:

sizeof(a) =1

sizeof(b)=1

sizeof(c)=4

sizeof(d)=8

上面是在VC++6.0编译的结果,但是在Dev-C++和Code::Blocks下得出的结果是 sizeof( d ) = 4

为什么会出现这种结果呢?初学者肯定会很烦恼是吗?类a,b明明是空类,它的大小应该为为0,为什么 编译器输出的结果为1呢?这就是我们刚才所说的实例化的原因(空类同样可以被实例化),每个实例在内存中都有一个独一无二的地址,为了达到这个目的,编译器往往会给一个空类隐含的加一个字节,这样空类在实例化后在内存得到了独一无二的地址.所以a,b的大小为1.

  • 虚函数

[cpp]
#include<iostream>
using namespace std;
class A
{
public:
   virtual void aa(){}
private:
   char k[3];
};
class B: public A
{
public:
   virtual void bb(){}
};
int main()
{
   cout<<"A's size is "<<sizeof(A)<<endl;
   cout<<"B's size is "<<sizeof(B)<<endl;
   return 0;
}
VS和gcc下执行结果:

A's size is 8

B's size is 8

说明:有虚函数的类有个virtual table(虚函数表),里面包含了类的所有虚函数,类中有个virtual table pointers,通常成为vptr指向这个virtual table,占用4个字节的大小。成员类B public继承于A,类B的虚函数表里实际上有两个虚函数A::aa()和B::bb(),类B的大小等于char k[3]的大小加上一个指向虚函数表指针vptr的大小,考虑内存对齐为8。

  • 虚继承

[cpp]
#include<iostream>
using namespace std;
class A
{
public:
   virtual void aa(){}
private:
   char k[3];
};
class B: virtual public A
{
public:
   virtual void bb(){}
};
int main()
{
   cout<<"A's size is "<<sizeof(A)<<endl;
   cout<<"B's size is "<<sizeof(B)<<endl;
   return 0;
}
vs和gcc下
执行结果:

A's size is 8
       B's size is 12
说明:类B里包含,继承的char k[3],继承的虚函数,类B的虚函数表里有A::aa(),因为是虚继承,还有一个指向父类的指针,该指针为指向虚基类的指针(Pointer to virtual base class)。考虑内存对齐,总大小为12。

  • 多重继承

#include <iostream>
using namespace std;
class A
{
   char k[3];
   public:
   virtual void aa(){};
};
class B
{
   char q[3];
   public:
   virtual void bb();
};
class C: public A,public B
{
   char j[3];
   public:
   virtual void cc(){};
};
int main()
{
   cout<<"sizeof(A):"<<sizeof(A)<<endl;
   cout<<"sizeof(B):"<<sizeof(B)<<endl;
   cout<<"sizeof(C):"<<sizeof(C)<<endl;
   return 0;
}


像这种继承方式,在类C中会维护两个虚函数指针,第一个指向第一个基类的虚函数表(并且带上在类C中定义的虚函数),第二个指针指向第二个基类(B)的虚函数表...其他的类似。

c++中求类大小,虚函数表指针_类大小

综合例子:

#include <iostream>
using namespace std;
class A
{
char k[3];
public:
virtual void f(){};
};
class B : public virtual A
{
   char i[3];
public:
virtual void f1(){};
};
class C: public virtual  A{
//virtual void f(){};
char j[3];
public:
virtual void t(){};
};
class D: public B,public C
{
   char g[3];
   public:
   virtual void s();
};
int main()
{
   cout<<sizeof(A)<<endl;
  cout<<sizeof(B)<<endl;
  cout<<sizeof(C)<<endl;
  cout<<sizeof(D)<<endl;
 return 0;
}

最后得到的结果是  8 16 16 28

最主要的是sizeof(D): 4个char数组,对齐后是16,又是多重继承,那么有两个虚函数表的指针,又需要维护一分A类的指针,那么是16+4*2+4=28...采用虚继承,目的就是为了解决二义性和减小内存开销,所以在D中只维护一份A的指针便可。

c++中求类大小,虚函数表指针_类大小_02