C++类所占内存大小计算


说明:笔者的操作系统是32位的。

class A {};
sizeof( A ) = ?
sizeof( A ) = 1
明明是空类,为什么编译器说它是1呢?
空类同样可以实例化,每个实例在内存中都有一个独一无二的地址,为了达到这个目的,编译器往往会给一个空类隐含的加一个字节,这样空类在实例化后在内存得到了独一无二的地址.所以sizeof( A )的大小为1.

 

class B 
 {
 public:
   B() {}
   ~B() {}
   void MemberFuncTest( int para ) { }
   static void StaticMemFuncTest( int para ){  }
 };
 sizeof( B ) = ?
 sizeof( B ) = 1


类的非虚成员函数是不计算在内的,不管它是否静态。

class C 
 {
  C(){}
  virtual ~C() {}
 };
 sizeof( B ) = ?
 sizeof( B ) = 4


类D有一个虚函数,存在虚函数的类都有一个一维的虚函数表叫虚表,虚表里存放的就是虚函数的地址了,因此,虚表是属于类的。这样的类对象的前四个字节是一个指向虚表的指针,类内部必须得保存这个虚表的起始指针。在32位的系统分配给虚表指针的大小为4个字节,所以最后得到类C的大小为4.

class D 
 {
  D(){}
  virtual ~D() {}
  virtual int VirtualMemFuncTest1()=0;
  virtual int VirtualMemFuncTest2()=0;
  virtual int VirtualMemFuncTest3()=0;
 };
 sizeof( D ) = ?
 sizeof( D ) = 4


原理同类C,不管类里面有多少个虚函数,类内部只要保存虚表的起始地址即可,虚函数地址都可以通过偏移等算法获得。

class E
 {
  int  m_Int;
  char m_Char;
 };
 sizeof( E ) = ?
 sizeof( E ) = 8


32位的操作系统int占4个字节,char占一个字节,加上内存对齐的3字节,为8字节。

class F : public E
 {
  static int s_data ;
 };
 int F::s_data=100;
 sizeof( F ) = ?
 sizeof( F ) = 8


类F为什么跟类E一样大呢?类F的静态数据成员被编译器放在程序的一个global data members中,它是类的一个数据成员,但是它不影响类的大小,不管这个类实际产生了多少实例还是派生了多少新的类,静态成员数据在类中永远只有一个实体存在,而类的非静态数据成员只有被实例化的时候,他们才存在.但是类的静态数据成员一旦被声明,无论类是否被实例化,它都已存在.可以这么说,类的静态数据成员是一种特殊的全局变量.

class G : public E
 {
  virtual int VirtualMemFuncTest1(int para)=0;
  int m_Int;
 };
 class H : public G
 {
  int m_Int;
 };
 sizeof( G ) = ?
 sizeof( H ) = ?
 sizeof( G ) = 16
 sizeof( H ) = 20


可以看出子类的大小是本身成员的大小再加上父类成员的大小.如果父类还有父类,也加上父类的父类,这样一直递归下去。

class I : public D
 {
  virtual int VirtualMemFuncTest1()=0;
  virtual int VirtualMemFuncTest2()=0;
 };
 sizeof( I ) = ?
 sizeof( I ) = 4


父类子类工享一个虚函数指针,虚函数指针保留一个即可。

总结:
空的类也是会占用内存空间的,而且大小是1,原因是C++要求每个实例在内存中都有独一无二的地址。
(一)类内部的成员变量:
普通的变量:是要占用内存的,但是要注意内存对齐(这点和struct类型很相似)。
static修饰的静态变量:不占用内存,原因是编译器将其放在全局变量区。
从父类继承的变量:计算进子类中
(二)类内部的成员函数:
非虚函数(构造函数、静态函数、成员函数等):不占用内存。
虚函数:要占用4个字节(32位的操作系统),用来指定虚拟函数表的入口地址。跟虚函数的个数没有关系。父类子类工享一个虚函数指针。

        构成对象本身的只有数据,任何成员函数都不隶属于任何一个对象,非静态成员函数与对象的关系就是绑定,绑定的中介就是this指针。成员函数为该类所有对象共享,不仅是处于简化语言实现、节省存储的目的,而且是为了使同类对象有一致的行为。同类对象的行为虽然一致,但是操作不同的数据成员。


测试代码如下:


<span style="font-size:18px;">/*
 * file name   : main.cpp
 * description : test the size of c++'s class
 * create on   : 2012-05-31
 * create by   : chenchong
 * email         : vision_chen@yeah.net
 */
  
#include<iostream>
  
using namespace
  
class
  
class
{  
public:  
  B() {}  
  ~B() {}  
void MemberFuncTest( int
static void StaticMemFuncTest( int
};  
  
class
{  
 C(){}  
virtual
};  
  
class
{  
 D(){}  
virtual
virtual int
virtual int
virtual int
};  
  
class
{  
int
char
};  
  
class F : public
{  
static int
};  
int
  
class G : public
{  
virtual int VirtualMemFuncTest1(int
int
};  
class H : public
{  
int
};  
  
class I : public
{  
virtual int
virtual int
};  
  
int main( int argc, char
{  
"sizeof( A ) = "<<sizeof( A )<<endl;  
"sizeof( B ) = "<<sizeof( B )<<endl;  
"sizeof( C ) = "<<sizeof( C )<<endl;  
"sizeof( D ) = "<<sizeof( D )<<endl;  
"sizeof( E ) = "<<sizeof( E )<<endl;  
"sizeof( F ) = "<<sizeof( F )<<endl;  
"sizeof( G ) = "<<sizeof( G )<<endl;  
"sizeof( H ) = "<<sizeof( H )<<endl;  
"sizeof( I ) = "<<sizeof( I )<<endl;  
  
#if defined( _WIN32 )
"pause");  
#endif
return
}  
  
</span>


 

Windows 7 32位 VC 2010运行结果:

类所占内存大小_虚表

Linux(cent os 6.2 32位)运行结果:

 

类所占内存大小_父类_02