【基础】类或结构体 大小判定

一、概述

  • 类所占内存的大小是由成员变量(静态变量除外)决定的,成员函数是不计算在内的。

【原因】:成员函数还是以一般的函数一样的存在。a.fun()是通过fun(a.this)来调用的。所谓成员函数只是在名义上是类里的。其实成员函数的大小不在类的对象里面,同一个类的多个对象共享函数代码。而我们访问类的成员函数是通过类里面的一个指针实现,而这个指针指向的是一个table,table里面记录的各个成员函数的地址( 具体可以看多态函数的实现 )。所以我们访问成员函数是间接获得地址的。所以这样也就增加了一定的时间开销,这也就是为什么我们提倡把一些简短的,调用频率高的函数声明为inline形式(内联函数)【见章节:内联函数】

二、事例分析 - 类

2.1、空

class Test_null
{
};
  • c++要求每个实例在内存中都有独一无二的地址,因此空类也会被实例化。

【原因】:编译器会给空类隐含的添加一个字节,这样空类实例化之后就有了独一无二的地址了。所以空类的sizeof为1。
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.2、仅成员变量

class Test_null
{
    int a;
    char b;
};
  • int 占 4字节,char占一字节,补齐3字节(遵循内存对齐原则)
  • static修饰的静态变量:不占用内容,原因是编译器将其放在全局变量区
    在这里插入图片描述

2.3、成员变量 + 成员函数 + 虚函数

class Test_null
{
public:
    void funb();
    virtual void func() = 0;
private:
    char b;
    int a;
};
  • 成员函数不占空间,

==其实类的成员函数 实际上与 普通的全局函数一样。
只不过编译器在编译的时候,会在成员函数上加一个参数,传入这个对象的指针。
==
成员函数地址是全局已知的,对象的内存空间里根本无须保存成员函数地址。

  • 所有虚函数均通过vptr指针索引,所以只计算vptr
  • 64位操作系统 指针大小为8

在这里插入图片描述

2.4、继承 or 菱形继承

  • 子类的大小是本身成员变量的大小加上父类的大小,父类子类共享一个虚函数指针
  • 菱形继承的话,为了提高实例在内存中的存取效率.类的大小往往被调整到系统的整数倍.并采取就近的法则,离哪个最近的倍数,就是该类的大小,即大小为5的话,会调整为 8
    在这里插入图片描述

三、事例分析 - 结构体

3.1、为什么要存在内存对齐呢?

结构体存在内存对齐,类(对象)也如此。

【原因】:如果不考虑对齐,应该是以下方式存储的:

char A; 
int B; 

在这里插入图片描述

因为计算机的字长是4字节(一次处理的二进制数,不同计算机不同)的,所以在处理变量A与B时的过程可能大致为:

  • A:将0x00-0x03共32位读入寄存器,再通过左移24位再右移24位运算得到a的值(或与0x000000FF做与运算)
  • B:将0x00-0x03这32位读入寄存器,通过位运算得到低24位的值;再将0x04-0x07这32位读入寄存器,通过位运算得到高8位的值;再与最先得到的24位做位运算,才可得到整个32位的值。
  • 过程就会非常麻烦,因此牺牲几个字节,来提高效率。

3.2、长度分析

typedef struct T
{ 
    char c; //本身长度1字节 
    __int64 d;  //本身长度8字节
    int e;  //本身长度4字节
    short f;  //本身长度2字节
    char g;  //本身长度1字节
    short h;  //本身长度2字节
}; 

在这里插入图片描述

可是若申请的是T结构体数组,那么会出现下面的情况:即会出现边界不对称
在这里插入图片描述

因此最终的对齐方法为:结构体整体为最大成员的整数倍

在这里插入图片描述
最后:sizeof(T)==0x20

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值