C++ 类的大小 原理+详细计算示例

大小的组成

类的大小受:基类,成员,虚基表指针,虚函数表指针 影响。

计算方式

需要按照下列要素对齐和规则计算对齐:

对齐要素

编译器默认对齐数 = 根据环境改变,一般32位为4,64位为8。

有效对齐数 = 编译器默认对齐数(根据环境改变,一般32位为4,64位为8)与 该成员所占字节数的较小值。

最大对齐数 = 最大成员大小 与 编译器默认对齐数取较小值。

对齐规则

1.每个元素的起始偏移量 是该元素当前有效对齐数的整数倍。

2.类的大小是最大对齐数的整数倍。

每种情况下的计算示例

统一环境为32位机器。

不考虑继承多态

最简单不要对齐的例子

cpp 复制代码
class A
{
    int a;
};

int a 起始偏移量为0,是有效对齐数4(min(4,8))的0倍。

变量a占偏移量为0,1,2,3的字节,共大小的4字节为**最小有效对齐数(**4)的整数倍。

需要对齐的例子

对齐偏移量
cpp 复制代码
class A
{
    bool a;
    int b;
};

bool a的起始偏移量为0,占用偏移量为0的字节。

int b的起始偏移量为1,不是当前有效对齐数(min(4,8))的整数倍

偏移量为1,2,3的字节空出,int b从占用偏移量为4,5,6,7的字节。

最终大小为8,为对齐数4的整数倍。

对齐总大小
cpp 复制代码
class A
{
    int* a;
    bool b;
};

int* a占用偏移量为0,1,2,3的字节。

bool b占用偏移量为4的字节。

总大小为5,当前最大对齐数为int*大小与默认对齐数的较小值4,而5不是4的整数倍,故对齐后大小为8。

考虑继承多态

虚函数表与虚基表亦为类的成员(隐藏成员)故需要考虑对齐,聚焦于类的大小,本文就不再阐述继承多态的实现了。

非虚继承

cpp 复制代码
class A
{
    virtual void func() { ; }
    int* a;
    bool b;
};//size:8
class B : public A
{
    virtual void func()override { ; }
    int c;
};

因为不是虚拟继承,B中只继承A的成员。

a占偏移量0~3,b占4,c占8~11。

因为重写了func,故隐藏的虚函数表指针占12~15。

总大小为16刚好为最大对齐数(最大成员大小为4,默认对齐数为4,取最小还是4)的整数倍。

虚继承

cpp 复制代码
class A
{
    virtual void func() { ; }
    int* a;
    bool b;
};//size:8
class B : virtual public A //虚继承
{
    virtual void func()override { ; }
    int c;
};

虚拟继承实现方式为虚基表指针指向虚基类在类中的偏移量,不清楚的可以先移步,笔者的这篇文章中有详细阐述。

彻底理解虚拟继承http://t.csdnimg.cn/4SpKBc占偏移量0~3的字节。

虚函数表指针占4~7的字节。

虚基表指针占8~11的字节。

虚基类A占12~19的字节(当前最大对齐数为min(8,4)12为4的倍数)。

最大对齐数为min(4,8)=4。

20为最大对齐数的整数倍,最终大小为20。

相关推荐
txinyu的博客3 小时前
解析业务层的key冲突问题
开发语言·c++·分布式
码不停蹄Zzz3 小时前
C语言第1章
c语言·开发语言
666HZ6664 小时前
数据结构2.0 线性表
c语言·数据结构·算法
SmartRadio4 小时前
ESP32添加修改蓝牙名称和获取蓝牙连接状态的AT命令-完整UART BLE服务功能后的完整`main.c`代码
c语言·开发语言·c++·esp32·ble
charlie1145141915 小时前
嵌入式的现代C++教程——constexpr与设计技巧
开发语言·c++·笔记·单片机·学习·算法·嵌入式
济6176 小时前
嵌入式C语言(第二期)
c语言
Dillon Dong8 小时前
STM32嵌入式:使用 MT29F8G08ABACAWP NAND 的FLASH全面指南
c语言·stm32
CSDN_RTKLIB8 小时前
【字符编码】有无BOM的UTF-8
c++
Chary20169 小时前
opengl 学习资料路径
c++·opengl
zhongvv9 小时前
对单片机C语言指针的一些理解
c语言·数据结构·单片机·指针·汇编语言