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

  • 相关阅读:
    全程记录:今天尝试安装SharePoint Server 2007过程 ,安装成功了,但是开始使用碰到权限问题,应该算是BUg吧 无为而为
    IT人看《国富论》系列:第一篇之第九章:论资本利润,暴利或许意味着市场的调节已经失效了,比如房地产 无为而为
    组建InfoPath/SharePoint/WebParts项目组,已收到项目意向,欢迎每周至少有20小时左右的空余时间有项目经验者加入。 无为而为
    我有问题请教各位硬件高手:电脑呈现这个症状是不是电源的输出功率不够? 无为而为
    使用VS2005新功能的Tips:this.Validate();这一句话,让我找了好久。 无为而为
    MSF for CMMI Process Improvement项目体验: Work Items : Requirement (更新版) 无为而为
    等待新产品还是自己开发,这是个两难的问题 无为而为
    在播放器战争爆发之前:比较苹果的iTunes 6和微软Media Player 10 无为而为
    LCS管理员的工具:Live Communications Server 2005 with Service Pack 1 Resource Kit,比如追踪登陆过程 无为而为
    Ms sql 等待一定时间后取数据
  • 原文地址:https://www.cnblogs.com/yejianying/p/cpp_size_of_class.html
Copyright © 2020-2023  润新知