注意类大小与结构体大小还是有一些不同的,类里面还包含成员函数(特别是虚函数),结构体中一般只有数据成员。

首先明确各数据类型占多大的空间。例如int到底是占2字节还是4字节空间:

在TC里,int是2字节的(主要是因为TC是16位的,所以int类型也该是16位的)
VC++里,int是4字节的,因为现代操作系统下的软件大多是是32位。
64位的VC++,本来按理说,该是8字节的,但是可能为了维持32位的源代码移植到64位尽量不出错,所以也维持了4字节的长度。
至于其他有名的编译器,如gcc,我还没用过,你得查一查它所规定int的长度

或者利用sizeof(int)也可以计算出来。本人电脑上计算如下:

在C语言中存在关于结构体的存储空间大小是比较深入的话题,其中涉及计算机的基本原理、操作系统等。我认为对齐是C语言中让很多初学者都拿不准摸不透的问题,特别是在跨平台的情况下,对齐这种问题更加的复杂多变,每一种系统都有自己独特的对齐方式,在Windows中经常是以结构体重最大内置类型的存储单元的字节数作为对齐的基准,而在Linux中,所有的对齐都是以4个字节对齐。

那么在C++中的类的内存空间大小又有哪些特殊的问题呢?

首先,我认为对齐肯定也是其中的问题之一,对齐主要是为了加快读取的速度。

关于对齐这个我认为基本上已经是操作系统内定好的,既然Linux与Windows存在差别,那么在C++的类中,关于对齐肯定也会存在一定的差别。关于对齐我认为只要记住平时使用的系统的对齐准则就可以了,即:在Windows中经常是以结构体重最大内置类型的存储单元的字节数作为对齐的基准,而在Linux中,所有的对齐都是以4个字节对齐。

其次,我认为就应该讨论在基类中哪些成员占有存储空间,那些成员不占用内存空间?

在C++中占存储区间的主要是非static的数据对象,主要包括各种内置的数据类型,类对象等,类中的函数声明以及函数定义都不算内存空间。但是需要注意所有的virtual函数(虚函数)共享一段内存区域,一般来说是4个字节。为什么只是包含非static数据对象呢?因为static数据并不属于类的任何一个对象,它是类的属性,而不是具体某一个对象的属性,在整个内存区域中只有一个内存区域存储对应的static数据,也就是所有的类对象共享这个数据,所以不能算做具体某一个对象或者类型的内存空间。

因此可以认为基类对象的存储空间大小为:

    非static数据成员的大小 + 4 个字节(虚函数的存储空间)

当然这个大小不是所有数据成员大小的叠加,而是存在一个对齐问题,具体的应该参考相关的对齐文章。

最后,我认为肯定要关心一下派生类的存储空间了?

在C++中,继承类是一个比较有用的类,继承使得各种类在基类的基础上扩展,这时候派生类中包含了基类的信息,一般而言,在基类中存在虚函数时,派生类中继承了基类的虚函数,因此派生类中已经继承了派生类的虚函数。因此继承类中不能再添加虚函数的存储空间(因为所有的虚函数共享一块内存区域),而仅仅需要考虑派生类中心添加进来的非static数据成员的内存空间大小。

因此可以认为派生类对象的存储空间大小为:

    基类存储空间 + 派生类特有的非static数据成员的存储空间

   还有一类是比较特殊的情况,如果是虚继承的情况下,这时的存储空间大小就会发生变化。

    基类的存储空间 + 派生类特有的非static数据成员的存储空间 + 每一个类的虚函数存储空间。

下面我采用一些例子说明上面的问题:

  1. #include <iostream>
  2. using namespace std;
  3. class test
  4. {
  5. public:
  6. test();
  7. private:
  8. int a;
  9. char c;
  10. };
  11. int main()
  12. {
  13. cout << sizeof(test) << endl;
  14. //system("pause");//按Ctrl+F5
  15. ;
  16. }

上面的代码在linux以及windows下都会输出8,而不是输出5,这个是在C语言中已经讨论过的话题,但是说明对齐在C++中也是要考虑的。关于操作系统的差异在后面用一个统一的例子说明。

虚函数问题

为了讨论虚函数,我们在test类中添加一个虚析构函数,然后再测试结果。 

  1. class test
  2. {
  3. public:
  4. test();
  5. virtual ~test();
  6. private:
  7. int a;
  8. char c;
  9. };

这段代码与前面的代码没有什么区别,只是添加了一个虚函数,然后编译调试,这时候输出的结果12,也就是说增加了一个虚函数以后,类的数据成员增加了4个字节,那么是否是每一个虚函数都占有4个字节呢?其实是不会的,在test中加入一个新的虚函数virtual void get_a_c(),这时在输出的结果还是12,这说明所有的虚函数共享4个字节。

static数据

我们知道static数据是非对象的属性,而是类的属性,他不能算是某一个对象或者类型的存储空间,在类定义中只能声明,初始化只能在类外执行,当然有例外的。这也不做分析了。具体参看后面的大例子。

派生类的存储空间

派生类从基类中继承了很多成员,自己也会增加很多的成员,由于虚函数也会被继承下来,所以就是在派生类中不显式定义虚函数,在派生类中也会存在从基类继承下来的虚函数,因此虚函数不需要额外计算内存空间,而只需要增加基类的非static成员数据大小。定义如下面所示,该函数会输出20,刚好是添加的非static数据double d的存储空间大小。证明了上面的分析。

  1. #include <iostream>
  2. using namespace std;
  3. class test
  4. {
  5. public:
  6. test();
  7. virtual ~test();
  8. virtual void get_a_c();
  9. private:
  10. int a;
  11. char c;
  12. };
  13. class derived_test:public test
  14. {
  15. public:
  16. virtual ~derived_test();
  17. private:
  18. double d ;
  19. };
  20. int main()
  21. {
  22. cout << sizeof(derived_test) << endl;
  23. ;
  24. }

测试虚继承的类的大小:

  1. #include <iostream>
  2. using namespace std;
  3. class A
  4. {
  5. ];
  6. public:
  7. virtual void a(){};
  8. };
  9. class B : public virtual A
  10. {
  11. ];
  12. public:
  13. virtual void b(){}
  14. };
  15. class C: public virtual B
  16. {
  17. ];
  18. public:
  19. virtual void c(){}
  20. };
  21. int main()
  22. {
  23. cout << "sizeof(A): " << sizeof(A) << endl;
  24. cout << "sizeof(B): " << sizeof(B) << endl;
  25. cout << "sizeof(C): " << sizeof(C) << endl;
  26. ;
  27. }

输出结果为:

如果是虚继承的情况下,这时的存储空间大小就会发生变化。

    基类的存储空间 + 派生类特有的非static数据成员的存储空间 + 每一个类的虚函数存储空间。

另外,如果A类改成如下形式:

  1. class A
  2. {
  3. ];
  4. public:
  5. virtual void a(){};
  6. };

所占空间:12。存储空间模型如下:

注意这里以4字节作为基准,因为类中间有个虚函数,结构体不存在函数,所以就以基本的数据类型为基准。

顺便提一下类B的大小为什么是24?

1.类B是继承类A,所以先把A的大小计入,+12;

2.类B有个数据成员,根据内存对齐,+4;

3,类B有个函数成员,且是虚函数,因为与A的关系是虚继承关系,所以与父类A不共享虚表指针,得另外开辟一个虚表指针空间,指针大小4字节,+4

4.因为类A,类B是虚继承关系,所以类B必须开辟一个指向虚基类的指针指向虚基类A,+4

综上所述:类B的大小是24,类C的大小类推。不过注意这是在VC环境下测试的,如果在GCC环境下结果不同。可以参考另外一篇日志。

  1. class A
  2. {
  3. ];
  4. char t;
  5. public:
  6. virtual void a(){};
  7. };

所占空间:8。

  1. class A
  2. {
  3. ];
  4. char t;
  5. char t1;
  6. public:
  7. virtual void a(){};
  8. };

所占空间:12。

不解释了。

C++中类的内存空间大小(sizeof)分析的更多相关文章

  1. Android - 获取SD卡的内存空间大小

    获取SD卡的内存空间大小 //获得SD卡空间的信息 File path=Environment.getExternalStorageDirectory(); StatFs statFs=new Sta ...

  2. C++中一个类(非继承类)对象,所占内存空间大小

    离职后在家里带了半年多了,这半年多里没有编写过一行代码,倒是看过一些书,但是差不多也都是囫圃吞枣.房子也快要装修,也得赶快找一个工作了,不然养车,还要玩摄影,没收入的日子真是不好过啊.呵呵. 按惯例, ...

  3. Visual Studio 2017 如何 监控当前变量 占用内存空间大小

    在进行VS调试时 大家是否想知道当前变量 占用了内存多少空间呢 这对系统调优还是很有帮助的吧

  4. Java学习日记-2.3 基本数据类型和对象所占内存空间大小

    转自:http://www.newsmth.net/nForum/#!article/Java/324167

  5. goto,void,extern,sizeof分析

    goto: 程序的质量与goto出现的次数成反比,禁用 goto的副作用:破环了程序的结构化的顺序执行的过程,它有可能会跳过程序的应该执行的一些步骤. void: 修饰函数返回值和参数 c语言中没有定 ...

  6. C语言中指针占据内存空间问题

    以前一直有个疑问,指向不同类型的指针到底占用的内存空间是多大呢? 这个问题我多次问过老师,老师的答案是"指向不同类型的指针占据的内存空间大小不同",我一直很之一这个答案,今天我就做 ...

  7. 使用malloc函数或new运算符为链表结点分配内存空间

    目录 使用malloc函数或new运算符为链表结点分配内存空间 使用malloc函数或new运算符为链表结点分配内存空间 当我们定义链表结点类型后,如何在每次需要使用新结点时临时分配相应大小的内存空间 ...

  8. 虚函数列表: 取出方法 // 虚函数工作原理和(虚)继承类的内存占用大小计算 32位机器上 sizeof(void *) // 4byte

    #include <iostream> using namespace std; class A { public: A(){} virtual void geta(){ cout < ...

  9. PHP数组实际占用内存大小的分析

    一般来说,PHP数组的内存利用率只有 1/10, 也就是说,一个在C语言里面100M 内存的数组,在PHP里面就要1G.下面我们可以粗略的估算PHP数组占用内存的大小,首先我们测试1000个元素的整数 ...

随机推荐

  1. 使用ToolRunner运行Hadoop程序基本原理分析

    为了简化命令行方式运行作业,Hadoop自带了一些辅助类.GenericOptionsParser是一个类,用来解释常用的Hadoop命令行选项,并根据需要,为Configuration对象设置相应的 ...

  2. 自定义滚动条 niceScroll 配置参数

    配置参数 当调用“niceScroll”你可以传递一些参数来定制视觉方面: cursorcolor - 十六进制改变光标颜色,默认值是“#000000” cursoropacitymin - 改变不透 ...

  3. 帝国cms实现自动生成缩略图和自动分页功能

    无论你手工发布,还是采集而来,免不了要进行手工操作弄缩略图,不然标题图片没有,挺烦人的 只需一次设定,就可以在文章编辑框里自动勾选上分页和生成缩略图,免除你次次进行操作的麻烦,好了,废话不多说,上菜“ ...

  4. AutoResetEvent 类的使用说明

    AutoResetEvent 类 官方描述:通知正在等待的线程已发生事件 命名空间:System.Threading 程序集:mscorlib 继承于:System.Threading.WaitHan ...

  5. Oracle字符函数(转换大小写,替换等)

    在oracle中,有一些字符函数: upper(字符串):转换为大写lower(字符串):转换为小写initcap(字符串):首字母大写replace(字符串1,字符串2,字符串3):将串1中所有的串 ...

  6. 原 iOS面试题收集

    原 iOS面试题收集 发表于2年前(2013-07-22 13:47)   阅读(369) | 评论(0) 4人收藏此文章, 我要收藏 赞0 听云性能监测产品App.Server.CDN免费试用,绑定 ...

  7. C语言-cout<<"123"<<"45"<<endl;

    VC中头文件为:#include <iostream.h> 这个在c中没有.是C++引进的. cout<头文件#include中printf()类似. 只是不需要标明数据类型. en ...

  8. EXTJS 4.2 实现 gridpanel 鼠标悬停单元格以提示信息的方式显示单元格内容。

    由于gridpanel的单元格里的文字太多时候,都由省略号代替,就想实现如题的功能,经过反复实验,终于搞定了!直接上代码: me.on('itemmouseenter', function (view ...

  9. UML--核心视图之用例图

    如果说UML是一门语言,那么元素就是UML的基本词汇,视图就是语法. UML通过视图将基本元素组织在一起,形成有意义的句子. 静态视图,顾名思义,就是表达静态事物的.包括用例图.类图和包图. 用例图 ...

  10. VC++ 2013 开发windows窗体程序

    开发工具版本:Visual Studio Express 2013 for Windows Desktop 1. 新建Visual C++下面的"Win32 Project" 2. ...