这里记录一下怎么计算类对象的大小。

大概总结下,类的大小需要考虑以下内容:

  1. 非静态成员变量大小
  2. 数据对齐到多少位
  3. 有无虚函数(即需不需要指向虚函数表的指针,如果考虑继承的情况,则还需要看继承了多少个指向虚函数表的指针)

非静态成员变量大小

空类

首先我们看什么都没有的时候的例子:

class test{

};

可以看到,类实例化的对象的大小为1。这是因为即使类是空白类,编译器也会分配一个字节的空间来占位,用来和真正的空白/空变量区别开来(毕竟实例化其实就是分配一定的内存空间,如果没有分配空间,那么就和没有实例化差不多了)。不过注意的是,如果空白类作为基类被继承了的话,是不会对继承它的类的空间产生影响的,即在继承的一瞬间,基类大小变为0,而继承它的类的大小只与自己的成员变量有关(此处默认为单一继承):

#include <iostream>
#include <string> using namespace std; class test { }; class test2 : public test {
private:
int a = 2;
}; int main() {
test2 tmp;
cout << "size of class test " << sizeof(tmp) << endl;
getchar();
return 0;
}

只有成员变量

#include <iostream>
#include <string> using namespace std; class test3 {
private:
int a = 3;
float b = 3.0;
}; int main() {
test3 tmp;
cout << "size of class test " << sizeof(tmp) << endl;
getchar();
return 0;
}

可以看到,32位系统中,intfloat占4个字节,所以最终类的实例大小为8。

static静态成员变量对类大小的影响

#include <iostream>
#include <string> using namespace std; class test4 {
private:
int a = 3;
float b = 3.0;
static int c;
}; int main() {
test4 tmp;
cout << "size of class test " << sizeof(tmp) << endl;
getchar();
return 0;
}

可以看到,输出还是8,即便加上了静态成员变量。这是因为静态成员变量其实存放的地方是在别的地方(全局变量/静态变量区,毕竟要让所有实例可见),所以不会影响到实例的大小。

只有成员函数

class funcOnly {
public:
funcOnly() {};
~funcOnly() {};
private:
void boo() {};
};

可以看到,函数不占用类的空间,这里是1是因为编译器分配了1个字节来占位。我们还可以验证下:

于是,类的空间从1字节变成了4字节,不再是像空类那样的1字节了。

数据对齐到多少位

class test5 {
private:
char d;
int a = 3;
float b = 3.0;
static int c;
}; int main() {
test5 tmp;
cout << "size of class test " << sizeof(tmp) << endl;
getchar();
return 0;
}

虽然char只占用1个字节,但是因为存在数据对齐,所以需要补齐到4的倍数(补齐char到4字节,为了方便CPU计算)。另外,这里其实可以分化出另外几个情况,例如连续两个char放在一起:

以及分开来放:

可以看到,顺序对实例大小的影响。这是因为,如果两个char放在一起的话,那么编译器会将这两个char放在一起,然后补齐。如果不是连续放着的,那么会分别补齐到4字节。因此,尽量“凑”变量类型到4字节,这样可以让补齐后的实例大小小一些。另外,要注意的是,含有数组的时候是一个个地连续地放,而不是视为整体,所以如果有数组,例如:

class test8 {
private:
char d[12];
int a = 3;
};

再举个例子:

class test8 {
private:
char d[11];
int a = 3;
};

有数组的时候,先连续摆放好,然后再补齐。

注意,上面说到的补齐到4字节是因为类里面最大的类型就是int,是4个字节,如果有更大的,那么就要补齐到更大的字节对应的倍数,如:

这里出现了8字节的double,那么补齐到8字节。其实之所以补齐8字节,是因为我是在Windows平台下编译的,如果是Linux,即是用GCC,那么其实还是当类型大小超过4字节的时候,只要求起始地址是4的整数倍。

有无虚函数

这部分理解要结合虚函数相关的知识。

class funcOnly2 {
public:
funcOnly2() {};
virtual ~funcOnly2() {};
private:
void boo() {};
}; int main() {
funcOnly2 tmp;
cout << "size of class funcOnly2 " << sizeof(tmp) << endl;
getchar();
return 0;
}

这里因为多了个虚指针,所以大小为4,所以类大小要加上虚指针的4:

class funcOnly2 {
public:
funcOnly2() {};
virtual ~funcOnly2() {};
private:
void boo() {};
int br;
};

例如上面这样的,就是int的4加上虚指针的4。

总结

大概总结下,类的大小需要考虑以下内容:

  1. 所有非静态成员变量大小
  2. 数据对齐到多少位
  3. 有无虚函数(即需不需要指向虚函数表的指针,如果考虑继承的情况,则还需要看继承了多少个指向虚函数表的指针)

参考

C++中空类占一字节原因详解:建议看,对空白类的讲解比较详细

sizeof计算空间大小的总结

《C++ Primer 第5版》

C++类大小的计算的更多相关文章

  1. C++类对象大小的计算

    (一)常规类大小计算 C++类对象计算需要考虑很多东西,如成员变量大小,内存对齐,是否有虚函数,是否有虚继承等.接下来,我将对此举例说明. 以下内存测试环境为Win7+VS2012,操作系统为32位 ...

  2. Math类的数学计算功能

    //Math类的数学计算功能 public class MathTest { public static void main(String[] args) { /*----------下面是三角运算- ...

  3. struct和class内存大小的计算

    以下均是在VS2017下的结果 结构体内存大小的计算: 用例一: #include<stdio.h> union ss { int a; char b; }; struct MyStruc ...

  4. C++类大小

    对于C++中类的大小,主要针对于无成员的空类大小,编译器会对该类进行优化,情况主要分为是否有虚表(虚函数)两种类型,对于无虚函数的类,该类大小均为1个字节(编译器插入一个char表示该类的存在),而出 ...

  5. c++类大小问题

    1.空类 class A { }; 解析:类的实例化就是为每个实例在内存中分配一块地址:每个类在内存中都有唯一的标识,因此空类被实例化时,编译器会隐含地为其添加一个字节,以作区分. 2.虚函数类 cl ...

  6. CNN中感受野大小的计算

    1 感受野的概念 从直观上讲,感受野就是视觉感受区域的大小.在卷积神经网络中,感受野的定义是 卷积神经网络每一层输出的特征图(feature map)上的像素点在原始图像上映射的区域大小. 2 感受野 ...

  7. 【整理】C++虚函数及其继承、虚继承类大小

    参考文章: http://blog.chinaunix.net/uid-25132162-id-1564955.html http://blog.csdn.net/haoel/article/deta ...

  8. sizeof操作符-结构体与类大小

    导读 sizeof是C/C++一个难点,当在自定义类上应用sizeof操作符时,总会出现意想不到的结果,下面,我们就来探讨一下sizeof这个操作符! 目录 1. sizeof与strlen的区别 2 ...

  9. class类的sizeof计算

    class no_virtual { public: void fun1() const{} int fun2() const { return a; } private: int a; } clas ...

随机推荐

  1. Kattis - heapsoffun Heaps of Fun (概率密度函数+dp)

    题意:有一棵含有n个结点(n<=300)的根树,树上每个结点上的权值是从[0,ai](ai<=1e9)区间内随机的一个实数,问这棵树能形成一个最小堆的概率. 由于结点取值范围是1e9而且是 ...

  2. 【HDU6703】array

    题目大意:给定一个 N 个数字的排列,需要支持两种操作:对某个位置的数字 + 1e7,查询区间 [1, r] 中最小的不等于区间中任何一个数字的数. 题解:本题证明了对于 50W 的数据来说,\(O( ...

  3. 2018年最佳JavaScript数据可视化和图表库

    现在有很多图表库,但哪一个最好用?这可能取决于许多因素,如业务需求,数据类型,图表本身的目的等等.在本文中,每个JavaScript图表库将与一些关键因素进行比较,包括图表类型,商业或免费和开源状态. ...

  4. 【LuoguP4557】[JSOI2018]战争

    题目链接 题意 给你两个点集. q次询问 , 每次把其中一个点集往一个方向移动 , 问两个点集的凸包还有没有交. Sol 闵可夫斯基和板子题. 把问题做如下转换: 我们本来两个凸包相交是相当于是对于移 ...

  5. 任务Task、先后任务

    Task类似后台线程. using System; using System.Threading; using System.Threading.Tasks;//引用命名空间 namespace Co ...

  6. Python内置类属性

    __dict__ : 类的属性(包含一个字典,由类的数据属性组成) __doc__ :类的文档字符串 __name__: 类名 __module__: 类定义所在的模块(类的全名是'__main__. ...

  7. 2018 计蒜之道 初赛 第五场 A 贝壳找房搬家

    贝壳找房换了一个全新的办公室,每位员工的物品都已经通过搬家公司打包成了箱子,搬进了新的办公室了,所有的箱子堆放在一间屋子里(这里所有的箱子都是相同的正方体),我们可以把这堆箱子看成一个 x*y*z 的 ...

  8. cp:复制文件和目录

    cp 命令,主要用来复制文件和目录,同时借助某些选项,还可以实现复制整个目录,以及比对两文件的新旧而予以升级等功能. cp 命令的基本格式如下:cp [选项] 源文件 目标目录/文件 选项: -a:相 ...

  9. mongodb php增删改查基本操作

    $mongo = new Mongo(); $db = $mongo->selectDB('test'); $collection = $db->selectCollection('foo ...

  10. Xcode 4.1实用小工具:模拟网络连接和带宽

    暂无评论 适用于Mac OS X Lion的开发套件Xcode 4.1中,有个新鲜的小工具叫做Network Link Conditioner(网络连接调节器),是一款具有高度可定制性的辅助工具,让用 ...