派生和基础 class 对象的指针互换性以及标准的措辞

Pointer-interconvertibility of derived and base class objects and the Standard's wording on it

我试图了解何时可以通过指向 void 的指针将派生对象安全地转换为基子对象(我认为它应该与 reinterpret_cast 相同)。但是我能找到的标准对此的措辞让我感到困惑。首先,

Two objects a and b are pointer-interconvertible if:

— one is a standard-layout class object and the other is the first non-static data member of that object, or, if the object has no non-static data members, the first base class subobject of that object

由此无法得出可靠的结论,“或”是适用于“或”之前的整个子句还是仅适用于它的第二部分。这很重要,因为在没有非静态数据成员的情况下,我无法确定“标准布局 class 对象”是否必须与基本子对象进行指针互换。

但是在深入研究标准时我发现:

If a standard-layout class object has any non-static data members, its address is the same as the address of its first non-static data member. Otherwise, its address is the same as the address of its first base class subobject (if any).

这似乎更清楚需要“标准布局”。但仍然令人困惑。考虑以下代码:

class B { public: int b; };
class C : public B { public: int c; };

int main ()
{ 
    C c;
    B* b = &c;
    std::cout << &c << " address of standard-layout class object\n";
    std::cout << &c.c << " address of its first non-static data member\n";
    std::cout << b << " address of first base class subobject\n";
    return 0;
}

在 VS2019 上结果是:

009BFBF8 address of standard-layout class object
009BFBFC address of its first non-static data member
009BFBF8 address of first base class subobject

这不是标准所说的。你能解释一下吗?

重点在standard-layoutclass的定义中。 来自 http://www.cplusplus.com/reference/type_traits/is_standard_layout/:

A standard-layout class 是一个 class(用 class、结构或联合定义):

  • 没有虚函数也没有虚基classes.

  • 对其所有内容具有相同的访问控制(私有、受保护、public) non-static 数据成员。

  • 要么在最派生的 class 中没有 non-static 数据成员,要么 至多一个基数 class 有 non-static 个数据成员,或者没有基数 class 有 non-static 个数据成员。

  • 它的基础class(如果有的话)本身也是一个standard-layout class.

  • 并且,没有与其第一个 non-static 相同类型的基础 class 数据成员.

在你的例子中 class C 不匹配第三条规则,所以 它不是 standard-layout class.

此外,关于你关于 'or' 的问题,它仅适用于第二部分,即在 'or' 之后,声明仍然是关于 standard-layout class 对象,但是没有 non-static 个成员。