分类:

一个类,有成员变量:静态与非静态之分;而成员函数有三种:静态的、非静态的、虚的。
      那么这些个东西在内存中到底是如何分配的呢?
      以一个例子来说明:

[html]view plaincopyprint?

  1. #include"iostream.h"
  2. class CObject
  3. {
  4. public:
  5. static int a;
  6. CObject();
  7. ~CObject();
  8. void Fun();
  9. private:
  10. int m_count;
  11. int m_index;
  12. };
  13. void CObject::Fun()
  14. {
  15. cout<<"Fun\n"<<endl;
  16. }
  17. CObject::CObject()
  18. {
  19. cout<<"Construct!\n";
  20. }
  21. CObject::~CObject()
  22. {
  23. cout<<"Destruct!\n";
  24. }
  25. int CObject::a=1;
  26. void main()
  27. {
  28. cout<<"Sizeof(CObject):"<<sizeof(CObject)<<endl;
  29. //CObject::Fun();
  30. cout<<"CObject::a="<<CObject::a<<endl;
  31. CObject myObject;
  32. cout<<"sizeof(myObject):"<<sizeof(myObject)<<endl;
  33. cout<<"sizeof(int)"<<sizeof(int)<<endl;
  34. }

这是我的一段测试代码, 
运行结果是: 
Sizeof(CObject):8 
CObject::a=1 
Construct! 
sizeof(myObject):8 
sizeof(int)4 
Destruct! 
我有疑问如下: 
(1) C++中,应该是对象才会被分配内存空间吧??为什么CObject内存大小是8,刚好和两个 成员变量的大小之和一致!难道还没实例化的时候,类就 已经有了内存空间了? 
(2)当对象生成了之后,算出的内存大小怎么还是8,函数难道不占用内存空间吗?至少应该放个 函数指针在里面的吧?内存是怎样布局的?
(3) 静态成员应该是属于类的,怎么类的大小中没有包含静态成员的大小?
下面分别解答如下:
1)Sizeof(CObject)是在编译时就计算了的,一个类定义了,它所占的内存编译器就已经知道了,这时只是得到它占用的大小,并没有分配内存操作 。也可以这样想:编译器肯定知道大小了,这与分配内存空间无关,知道大小了,以后实例化了才能知道要分配多大。
2)类的普通成员、静态成员函数是不占类内存的,至于你说的函数指针在你的类中有 虚函数的时候存在一个 虚函数表指针,也就是说如果你的类里有虚函数则 sizeof(CObject)的值会增加4个字节。
其实 类的成员函数 实际上与 普通的 全局函数一样。 
只不过编译器在编译的时候,会在成员函数上加一个参数,传入这个对象的指针。
成员函数地址是全局已知的,对象的内存空间里根本无须保存成员函数地址。 
对成员函数(非虚函数)的调用在编译时就确定了。 
像 myObject.Fun() 这样的调用会被编译成形如 _CObject_Fun( &myObject ) 的样子。
函数是不算到sizeof中的,因为函数是代码,被各个对象共用,跟数据处理方式不同。对象中不必有函数指针,因为对象没必要知道它的各个函数的地址(调 用函数的是其他代码而不是该对象)。 
类的属性是指类的数据成员,他们是实例化一个对象时就为数据成员分配内存了,而且每个对象的数据成员是对立的,而成员函数是共有的~ 
静态成员函数与一般成员函数的唯一区别就是没有this指针,因此不能访问非静态数据成员。总之,程序中的所有函数都是位于代码区的。
3)静态成员并不属于某个对象,sizeof取的是对象大小。
知道了上面的时候,就可以改一下来看看:
我也补充一些: 
class CObject 

public: 
static int a; 
CObject(); 
~CObject(); 
void Fun(); 
private: 
double m_count;  //这里改成了double 
int  m_index; 
}; 
这个类用sizeof()测出来的大小是 2*sizeof(double)=16 
class CObject 

public: 
static int a; 
CObject(); 
~CObject(); 
void Fun(); 
private: 
char m_count;  //这里改成了char 
int  m_index; 
}; 
大小是2*sizeof(int)=8 
class CObject 

public: 
static int a; 
CObject(); 
~CObject(); 
void Fun(); 
private: 
double m_count;  //这里改成了double 
int  m_index; 
char  c; 
}; 
sizeof(char)+sizeof(int) <sizeof(double) 所以大小是2*sizeof(double) 
其实这里还有一个是内存对齐的问题。
空类大小是1。 
另外要注意的一些问题:

先看一个空的类占多少空间?

class Base
      {
      public:
      Base();
      ~Base();
      };

class Base { public: Base(); ~Base(); };

注意到我这里显示声明了构造跟析构,但是sizeof(Base)的结果是1.

因为一个空类也要实例化,所谓类的实例化就是在内存中分配一块地址,每个实例在内存中都有独一无二的地址。同样空类也会被实例化,所以编译器会给空类隐含 的添加一个字节,这样空类实例化之后就有了独一无二的地址了。所以空类的sizeof为1。

而析构函数,跟构造函数这些成员函数,是跟sizeof无关的,也不难理解因为我们的sizeof是针对实例,而普通成员函数,是针对类体的,一个类的成 员函数,多个实例也共用相同的函数指针,所以自然不能归为实例的大小,这在我的另一篇博文有提到。

接着看下面一段代码

[html]view plaincopyprint?

  1. class Base
  2. {
  3. public:
  4. Base();
  5. virtual ~Base();         //每个实例都有虚函数表
  6. void set_num(int num)    // 普通成员函数,为各实例公有,不归入sizeof统计
  7. {
  8. a=num;
  9. }
  10. private:
  11. int  a;                  //占4字节
  12. char *p;                 //4字节指针
  13. };
  14. class Derive:public Base
  15. {
  16. public:
  17. Derive():Base(){};
  18. ~Derive(){};
  19. private:
  20. static int st;         //非实例独占
  21. int  d;                     //占4字节
  22. char *p;                    //4字节指针
  23. };
  24. int main()
  25. {
  26. cout<<sizeof(Base)<<endl;
  27. cout<<sizeof(Derive)<<endl;
  28. return 0;
  29. }

class Base { public: Base(); virtual ~Base(); //每个实例都有虚函数表 void set_num(int num) //普通成员函数,为各实例公有,不归入sizeof统计 { a=num; } private: int a; //占4字节 char *p; //4字节指针 }; class Derive:public Base { public: Derive():Base(){}; ~Derive(){}; private: static int st; //非实例独占 int d; //占4字节 char *p; //4字节指针 }; int main() { cout<<sizeof(Base)<<endl; cout<<sizeof(Derive)<< endl; return 0; }

结果自然是

12

20

Base类里的int  a;char *p;占8个字节。

而虚析构函数virtual ~Base();的指针占4子字节。

其他成员函数不归入sizeof统计。

Derive类首先要具有Base类的部分,也就是占12字节。

int  d;char *p;占8字节

static int st;不归入sizeof统计

所以一共是20字节。

在考虑在Derive里加一个成员char c;

  1. class Derive:public Base
  2. {
  3. public:
  4. Derive():Base(){};
  5. ~Derive(){};
  6. private:
  7. static int st;
  8. int  d;
  9. char *p;
  10. char c;
  11. };

class Derive:public Base { public: Derive():Base(){}; ~Derive(){}; private: static int st; int d; char *p; char c; };

这个时候,结果就变成了

12

24

一个char c;增加了4字节,说明类的大小也遵守类似class字节对齐,的补齐规则。

具体的可以看我那篇《5分钟搞定字节对齐》

至此,我们可以归纳以下几个原则:

1.类的大小为类的非静态成员数据的类型大小之和,也 就是说静态成员数据不作考虑。

2.普通成员函数与sizeof无关。

3.虚函数由于要维护在虚函数表,所以要占据一个指针大小,也就是4字节。

4.类的总大小也遵守类似class字节对齐的,调整规则。

转载自:http://www.blue1000.com/bkhtml/c151/2010-11/69613.htm

类中内容在内存中到底是如何分配的呢?相关推荐

  1. JavaScript中数据在内存中的存储方式

    JavaScript中数据在内存中的存储方式 1.js数据类型分类 简单数据类型:Number.String.Boolean.Undefined.Null 复杂数据类型:Object.Array.Fu ...

  2. C语言中变量在内存中是如何存放的

    首先我们知道计算机有32位/64位,那这里的32位/64位代表什么意思呢? 其实这里的32位/63位代表地址线,如果你的电脑是32位的,就是地址总线宽度为32位,一次可以发送的一个数据是32位的,则寻 ...

  3. c语言中小数在内存中的存储,c语言中小数在内存中的存储

    转至:https://blog..net/tqs_1220/article/details/73550899 首先看float和double在内存中是怎么存储的? float:符号位(1位)+指数位( ...

  4. 解析C语言中数据在内存中的存储

    系列文章目录 文章目录 系列文章目录 前言 一.数据类型介绍 1.类型的基本归类 1.整形家族 2.浮点型家族 3.构造类型 4.指针类型 5.空类型 二.整型在内存中的存储 1.原码.反码.补码 2 ...

  5. C语言中数据在内存中的存储

    要想了解数据在内存中的存储的话,首先应该了解数据的类型. 下面介绍C语言中数据类型: 1.C语言中的基本内置类型: char //字符数据类型 大小为1个字节 short //短整型 大小为2个字节 ...

  6. java python 运行 内存_Python C Java中字符串在内存中的存储

    Python 昨天在讲Python的过程中,发现了一个小问题,当时课上没有解决,下面特意查阅资料解决了一下. a = "123" b = "123" print ...

  7. Java中数组在内存中的存放原理?

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/yangyong0717/article/details/79165685 Java中数组被实现为对象 ...

  8. Proteus中查看C51内存中变量的值 寄存器的值

    在调试状态下,调试选项卡中选择CPU 第一个是寄存器 第二个详见(SFR) 基础讲解: http://www.21ic.com/jichuzhishi/mcu/memory/2013-04-19/17 ...

  9. linux复制文件中内容吗,Linux中实现对文件内容的复制。。。

    //linux学习路上的初学者 //使用前你需要先创建好两个文件 1.txt 2.txt 并在1.txt里面写好内容. #include#include#include#include#include ...

最新文章

  1. Linux Linux程序练习十一(网络编程大文件发送UDP版)
  2. DeepMind 综述深度强化学习:智能体和人类相似度竟然如此高!
  3. VC++ 实现自定义消息
  4. spring boot中使用Pagehelper实现分页
  5. 「LibreOJ Round #11」Misaka Network 与测试 (网络流跑二分图匹配)
  6. Awesome Tools Site
  7. sublime text3安装插件 emmet
  8. pgsql中float4导致java程序精度丢失_Java基础系列02
  9. java 存储过程返回结果集_通过SQL“select * from”从java存储过程返回结果集
  10. mysql 参数 innodb_flush_log_at_trx_commit
  11. notepad格式化html代码快捷键,Notepad++中代码格式化插件NppAStyle使用介绍
  12. c++学习笔记(八)- map
  13. springboot 腾讯云短信平台SDK
  14. JVM--基础--19.4--垃圾收集器--Parallel Scavenge
  15. 视觉SLAM十四讲笔记-第四讲 李群与李代数
  16. 从杉数到滴滴——未入门算法工程师工作日记(快手篇)
  17. 直流无刷电机【一】从零开始上手
  18. B-树和B+树的区别
  19. 力扣算法学习计划打卡:第八天
  20. Leetcode 13 罗马数字转整数数字

热门文章

  1. android 版本权限差别,android apk 的root 权限和USB adb 权限的区别
  2. TIMING_04 时序约束的一般步骤
  3. c++判断整数翻转溢出_LeetCode7.整数反转(Reverse Integer)
  4. 项目管理excel_项目经理必备的6款项目管理软件
  5. python天天向上每十天休息一天_Python基础第十天
  6. 见识可能比聪明更重要!
  7. 三极管和MOS管有什么不一样?用MOS管还是三极管?
  8. DIY一只机器狗需要多少钱?最低仅900美元,斯坦福大学出品,代码已开源
  9. html 判断当前窗口是否是子窗口,C#的MDI窗体判断子窗体是否已经打开
  10. lrange是取出所有值并移除么_美欧日站点亚马逊物流库存绩效指标分数达标值将降低为 450...