在学习";有效C++";,当我了解到这样一个事实时,我首先感到惊讶:如果一个类有多个继承,那么当指针强制转换完成时,它的指针可能会偏移。虽然这不是一个容易掌握的概念,但我想我设法得到了它
然而,作者声称,即使在单继承类的指针强制转换中,这种偏移也可能发生。我想知道这样的情况会是什么,并希望知道背后的理由
当派生类将多态性引入类层次结构时,就会发生这种情况。考虑以下类别:
struct Foo
{
int a;
int b;
};
这个类不是多态的,因此实现不需要包括指向虚拟调度表的指针(实现虚拟调度的常用方法(。它将被这样放在内存中:
Foo
+---+
a | |
+---+
b | |
+---+
现在考虑一个继承自Foo
:的类
struct Bar : Foo
{
virtual ~Bar() = default;
};
此类是多态性的,因此此类的对象需要包括指向vtable的指针,以便进一步派生的类可以覆盖Bar
的虚拟成员函数。这意味着Bar
对象在内存中的布局如下:
Bar
+---------+
vtable pointer | |
+---------+
Foo subobject | +---+ |
| a | | |
| +---+ |
| b | | |
| +---+ |
+---------+
由于对象的Foo
子对象不在对象的开头,因此从指向Bar
对象的指针初始化的任何Foo*
都需要根据指针的大小进行调整,以便它实际指向Bar
对象的Foo
子对象。
实时演示
class B {
int a = 0;
};
class D : public B {
virtual ~D() = default;
};
D有一个虚拟成员。B没有。C++中动态调度的一个常见实现涉及在对象的开头保留一个指向函数地址表的隐藏指针。
这意味着B子对象的第一个字节不会在整个D对象的开头。指针强制转换需要根据vptr大小调整地址。