C++类的对象内存布局

1. 类对象的内存布局

在 C++ 中,一个类的对象在内存中的布局取决于类的成员变量类型、继承关系、以及是否涉及虚函数等因素。类对象的内存分布通常分为以下几个部分:

  1. 非静态成员变量:类的每个实例都会拥有这些成员变量,它们占据对象的实际内存空间。
  2. 虚函数表指针(vptr):如果类包含虚函数,编译器会为该类生成虚函数表(vtable)和一个指向该虚函数表的指针(vptr),指针通常是类对象的第一个成员。
  3. 继承:当类继承自基类时,派生类对象通常会包括基类的成员数据。
1.1 单一类对象的内存布局

假设我们有一个简单的类:

class MyClass {
public:
    int a;
    double b;
};

在 64 位系统中,MyClass 对象的内存布局可能如下:

成员名类型大小说明
aint4B整数类型,通常占用 4 字节
bdouble8B双精度浮点数,通常占用 8 字节

内存对齐:为了满足 CPU 对内存访问的效率要求,编译器通常会对数据进行对齐。在 64 位系统上,double 通常会要求按 8 字节对齐。因此,可能会有一些填充字节,确保内存对齐。

内存布局(假设没有填充字节的情况下):

a (4B)b (8B)
4B8B

实际内存可能会有填充(例如 4 字节填充),以满足对齐要求。

1.2 带有虚函数的类对象

如果类中有虚函数,编译器会为该类生成一个虚函数表(vtable),并在每个对象中包含一个指向该虚函数表的指针(vptr)。例如:

class MyClass {
public:
    virtual void foo() {}
    int a;
};

在该情况下,类的对象的内存布局可能如下:

vptr 指针 (8B)a (4B)
8B4B
  • vptr:指向虚函数表的指针,通常是对象内存的第一个部分。每个包含虚函数的类都会有一个虚函数表(vtable),虚函数表存储指向该类虚函数的指针。
  • a:类的成员变量。

2. 类的嵌套结构的内存布局

类对象的内存布局不仅受自身成员变量的影响,还会受到嵌套类(成员类)影响。如果一个类中定义了另一个类作为成员,外部类的内存布局将包含嵌套类的对象。

2.1 简单嵌套类

假设有一个类 Outer,它包含一个类 Inner 作为成员:

class Outer {
public:
    int a;
    class Inner {
    public:
        double b;
    };
    Inner inner;
};

在这个例子中,Outer 类包含 int 类型的成员 aInner 类型的成员 inner。其中,Inner 类有一个 double 类型的成员 b

内存布局:

a (4B)inner (嵌套类)
4Bb (8B)
  • a:外部类的成员,类型为 int,占 4 字节。
  • inner:嵌套类的对象,占 8 字节(包括 double 类型的成员 b)。

3. 继承类对象的内存布局

继承关系中的类对象布局比单一类和嵌套类更加复杂。继承涉及到基类的成员数据和派生类的成员数据,此外,还可能涉及虚函数表(vtable)。

3.1 没有虚函数的继承

如果没有虚函数,派生类对象的内存布局通常包括基类的成员变量和派生类的成员变量。假设有如下的基类和派生类:

class Base {
public:
    int a;
};

class Derived : public Base {
public:
    double b;
};

Derived 类对象的内存布局将包括 Base 类的成员 aDerived 类的成员 b

a (4B)b (8B)
4B8B
  • a:基类的成员,类型为 int,占 4 字节。
  • b:派生类的成员,类型为 double,占 8 字节。
3.2 有虚函数的继承

如果基类或派生类中有虚函数,则每个类的对象都会包含一个指向虚函数表的指针(vptr)。假设我们有如下的基类和派生类:

class Base {
public:
    virtual void foo() {}
    int a;
};

class Derived : public Base {
public:
    double b;
};

Derived 类的对象内存布局会更复杂,包含基类的 vptr 和成员变量,以及派生类的成员变量。内存布局可能如下:

vptr (8B)a (4B)b (8B)
8B4B8B
  • vptr:指向虚函数表的指针,通常是对象内存的第一个部分,基类的虚函数会放在虚函数表中,派生类会继承或覆盖它。
  • a:基类的成员,类型为 int,占 4 字节。
  • b:派生类的成员,类型为 double,占 8 字节。

4. 智能指针管理的类对象的内存布局

智能指针(如 std::shared_ptrstd::unique_ptrstd::weak_ptr)的内存布局会影响类对象的内存分配方式,尤其是在管理继承对象时。

  • std::shared_ptr:存储指向控制块的指针和对象指针。控制块包含引用计数和弱引用计数等信息。
  • std::unique_ptr:仅存储指向对象的原始指针,确保对象唯一所有权。
  • std::weak_ptr:仅存储指向控制块的指针,不增加引用计数。

5. 总结

情况内存布局
单一类对象类的成员变量(按类型和内存对齐规则排列)
带有虚函数的类vptr(虚函数表指针) + 类的成员变量
类嵌套结构外部类的成员 + 嵌套类对象的成员
继承类对象基类成员 + 派生类成员 + 虚函数表指针(如有虚函数)
智能指针std::shared_ptr:控制块指针 + 对象指针;std::weak_ptr:控制块指针;std::unique_ptr:对象指针
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值