C++类的大小

类本身是没有大小的。类的大小,指的是类的对象所占的大小。如果用sizeof运算符对一个类型名操作,得到的是具有该类型实体的大小。

类型 32位编译器 64位编译器
char 1个字节 1个字节
char*(即指针变量) 4个字节 8个字节
short int 2个字节 2个字节
int 4个字节 4个字节
unsigned int 4个字节 4个字节
float 4个字节 4个字节
double 8个字节 8个字节
long 4个字节 8个字节
long long 8个字节 8个字节
unsigned long 4个字节 8个字节

影响类大小的因素:

1. 普通成员变量
2. 虚函数:因为虚函数表指针带来的影响
3. 继承(单一继承,多重继承,重复继承,虚拟继承):虚继承对类的大小有影响,是因为虚基表指针带来的影响
4. 字节对齐

不影响类大小的因素:

1. 静态成员变量
2. 静态成员函数
3. 普通成员函数
//64位系统
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class A {
    A();
    ~A();
public:
    virtual void fun(); //大小:8
private:
    int a; // 成员变量1,大小:4
    char *b; // 成员变量2,大小:8
    float c; // 成员变量3,大小:4
    double d; // 成员变量4,大小:8
    long e; // 成员变量5,大小:8
    char f; // 成员变量6,大小:1
    std::vector<std::string> g; // 成员变量7,大小:24, 取决于vector类的大小
};
class B : virtual public A
{
    B();
    ~B();
private:
    char a;
};

class C : virtual public A, virtual public B
{
    C();
    ~C();
private:
    int a;
};

int main()
{
    cout << "类A的大小: " << sizeof(A) << endl;
    cout << "类B的大小: " << sizeof(B) << endl;
    cout << "类C的大小: " << sizeof(C) << endl;
    return 0;
}
//结果
//只有成员变量1和2,4+8=12,但是由于需要字节对齐,所以大小为8+8=16
//只有成员变量6和7,1+24=25,但是由于需要字节对齐,所以大小为8+24=32
//只有成员变量1和6,4+1=5,但是由于需要字节对齐,所以大小为4+4=8
//只有虚函数成员变量1和6,8+4+1=13,但是由于需要字节对齐,所以大小为8+4+4=16

字体对齐原则:

对于结构体类型与类对象的对齐原则:使用成员当中最大的对齐字节来对齐。(前提是不超过8字节,当超过8字节,则采用8字节对齐)
指定对齐字节值: 意思是指使用了宏 #pragma pack(n)来指定的对齐值

虚函数:

类的大小为8。含有多个虚函数,类的大小依然为8,原因:
虚函数是通过虚函数表实现的,虚函数表实际上是一个函数指针数组,它保存了本类中的虚函数的地址。虚函数表属于类中而不属于类的某个实例,所以不会为每个实例专门生成一个虚函数表,但每个类的实例中保存指向了这个虚函数表的指针(所以包含虚函数的对象的大小会增加一个指针的大小),而且这个指针保存在对象实例空间的最前面。

继承

1. 单一继承/多重继承:子类的大小为自己的和所继承的类的成员按对齐方式结合
2. 重复继承:不会计算重复的
3. 虚拟继承:在多重继承中,如果发生了如:类B继承类A,类C继承类A,类D同时继承了类B和类C。最终在类D中就有了两份类A的成员,这在程序中是不能容忍的。当然解决这个问题的方法就是利用虚继承。

空类的大小为1:

原因是为了让对象的实例能够相互区别。空类同样能够被实例化,并且每个实例在内存中都有独一无二的地址,因此,编译器会给空类隐含加一个字节,这样空类实例化之后就会拥有独一无二的内存地址。
如果没有这一个字节的占位,那么空类就无所谓实例化了,因为实例化的过程就是在内存中分配一块地址。
当空类作为另一个类的成员时,大小计算在内。但是当一个类继承空类时:大小不计算,空白基类最优化(EBO/EBCO)
posted on 2020-07-20 20:46  JJ_S  阅读(744)  评论(1编辑  收藏  举报