具有单一继承的 class 的指针转换偏移量

Pointer casting offset of a class with single inheritance

在学习《Effective C++》时,我首先惊讶的是,如果一个class具有多重继承,那么当指针转换完成时,它的指针可能会发生偏移。虽然这个概念不太容易掌握,但我想我还是搞定了。

然而,作者声称即使在单继承class的指针转换中也可能发生这种偏移。我想知道这样的情况会怎样,想知道背后的原理。

class B {
  int a = 0;
};

class D : public B {
  virtual ~D() = default;
};

D有虚拟会员。 B 没有。 C++ 中动态分派的常见实现涉及在对象的开头保留一个指向 table 函数地址的隐藏指针。

这意味着 B 子对象的第一个字节不会在完整的 D 对象的开头。指针转换需要根据 vptr 大小调整地址。

当派生的 class 将多态性引入 class 层次结构时,就会发生这种情况。考虑以下 class:

struct Foo
{
    int a;
    int b;
};

这个 class 不是多态的,因此实现不需要包含指向虚拟分派的指针 table(实现虚拟分派的常用方法)。它在内存中的布局是这样的:

  Foo
  +---+
a |   |
  +---+
b |   |
  +---+

现在考虑继承自 Foo 的 class:

struct Bar : Foo
{
    virtual ~Bar() = default;
};

这个 class 多态的,所以这个 class 的对象需要包含一个指向 vtable 的指针,以便进一步派生 classes 可以覆盖 Bar 的虚拟成员函数。这意味着 Bar 个对象将像这样在内存中布局:

               Bar
               +---------+
vtable pointer |         |
               +---------+
 Foo subobject |   +---+ |
               | a |   | |
               |   +---+ |
               | b |   | |
               |   +---+ |
               +---------+

由于对象的 Foo 子对象不在对象的开头,任何从指向 Bar 对象的指针初始化的 Foo* 都需要调整大小一个指针,使其实际指向 Bar 对象的 Foo 子对象。

Live Demo