C++类大小的计算

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

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

  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版》

原文地址:https://www.cnblogs.com/yejianying/p/cpp_size_of_class.html

时间: 2024-08-02 12:20:54

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

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

参考文章: http://blog.chinaunix.net/uid-25132162-id-1564955.html http://blog.csdn.net/haoel/article/details/1948051/ 一.虚函数与继承 1.空类,空类单继承,空类多继承的sizeof #include <iostream> using namespace std; class Base1 { }; class Base2 { }; class Derived1:public Base1

文件大小的计算和文件夹大小的计算

1读取本地documents文件里文件夹的大小(我们可以利用NSDirectoryEnumerator这个类) NSString * Docupath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; //    一般不要吧文件直接放到documents文件夹下,要创建新的文件夹 NSString * filePath = [Docupath stringByAppendin

struct和class内存大小的计算

结构体内存大小的计算: 用例一: #include<stdio.h> union ss { int a; char b; }; struct MyStruct { int temp1;//4个字节 char temp2;//一个字节,补齐3个字节 ss aa;//4个字节 char temp3;//一个字节 char temp4;//一个字节,补齐两个字节 }; int main() { printf("%d", sizeof(MyStruct)); return 0; }

sizeof 和类继承 虚继承 求类大小

代码: #include <iostream> using namespace std; /* class a{ float k; // 4字节 virtual void foo(){} //有一个4字节的指针指向自己的虚函数表 }; class b : virtual public a{ virtual void f(){} }; 有这样的一个指针vptr_b_a,这个指针叫虚类指针,也是四个字节:还要包括类a的字节数,所以类b的字节数就求出来了. 运行结果: 8 16 */ /* clas

c++类大小问题

1.空类 class A { }; sizeof(A); //1 解析:类的实例化就是为每个实例在内存中分配一块地址:每个类在内存中都有唯一的标识,因此空类被实例化时,编译器会隐含地为其添加一个字节,以作区分. 2.虚函数类 class A { virtual void Fun(); }; sizeof(A); //4 解析:当一个类中包含虚函数时,会有一个指向其虚函数表的指针vptr,系统为类指针分配大小为4个字节(即使有多个虚函数). 3.普通数据成员 class A { int a; ch

MySQL key_len 大小的计算

背景: 当用Explain查看SQL的执行计划时,里面有列显示了 key_len 的值,根据这个值可以判断索引的长度,在组合索引里面可以更清楚的了解到了哪部分字段使用到了索引. 环境: CREATE TABLE `tmp_0612` ( `id` int(11) NOT NULL, `name` varchar(10) DEFAULT NULL, `age` int(11) DEFAULT NULL, `address` varchar(100) DEFAULT NULL, PRIMARY KE

【c语言】位段大小的计算以及宏的应用

// 位段大小的计算以及宏的应用 #include <stdio.h> #include <malloc.h> #define MAX_SIZE A+B struct _Record_Struct { unsigned char Env_Alarm_ID : 4; unsigned char Paral : 2; unsigned char state; unsigned char avail : 1; }*Env_Alarm_Record; int main() { int A

计算机中地址和内存大小的计算和编译出来的数据段

由地址计算内存大小(消除模糊认知) 在计算机中一个地址代表一个字节的内存的位置,即这个byte的门牌号,所以如果给出地址空间的起始地址是可以计算出内存大小的,比如STM32中Flash可编程的地址是从0x0800 0000开始到0x0801FFFF结束的所以内存大小的计算过程如下: 地址差 = 结束地址 - 开始地址  =  0x0001FFFF:他们可以表示的Byte的个数是N = 0x0001 FFFF + 1即0x00020000将N变换为十进制是131072. 内存大小 = N/1024

Java对象大小的计算方式

Java对象大小的计算方式首先我们需要知道的是 Java 对象是包含三部分数据的:?1.对象头?2.实例数据?3.对齐填充(可能没有,因为 java 中规定对象的起始地址必须是 8 bytes 的正数倍)? 对于普通对象而言,对象头中包括 mark word(8 bytes).kclass(没有开启压缩的时候是 8 bytes,开启压缩了的话,就是 4 bytes),如果是数组类型的对象话,这里还有一个数组长度字段,4字节.? 在 JDK6 64位 23 update+ 之后都默认开启了指针压缩