【问题标题】:Pointer-interconvertibility of derived and base class objects and the Standard's wording on it派生类和基类对象的指针互转换性和标准的措辞
【发布时间】:2021-01-22 06:29:51
【问题描述】:

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

如果满足以下条件,两个对象 a 和 b 是指针可互转换的:

——一个是标准布局类对象,另一个是该对象的第一个非静态数据成员,或者,如果该对象没有非静态数据成员,则该对象的第一个基类子对象

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

但在进一步挖掘标准时,我发现:

如果标准布局类对象有任何非静态数据成员,则其地址与其第一个非静态数据成员的地址相同。否则,它的地址与其第一个基类子对象的地址相同(如果有的话)。

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

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

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

【问题讨论】:

  • 对于这两个报价标准布局是一个前提。当我在这里尝试时,看起来C 不是标准布局:godbolt.org/z/3W796T
  • @idclev,在 VS 上它还提供false。但是在从 B 或 C 中删除一个成员后,它会解析为 true
  • C 是标准布局的情况下,你能得到你所期望的吗?
  • C 不是标准布局类,因此第二段没有说明您的示例。
  • 顺便说一句,你的动机有点不清楚。你不需要reinterpret_cast 也不需要绕道void* 在基础和派生之间转换

标签: c++ class inheritance casting standards


【解决方案1】:

重点在于标准布局类的定义。 来自http://www.cplusplus.com/reference/type_traits/is_standard_layout/

标准布局类是一个类(用类、结构或联合定义):

  • 没有虚函数,也没有虚基类。

  • 对所有其拥有相同的访问控制(私有、受保护、公共) 非静态数据成员。

  • 在最派生类中没有非静态数据成员,并且 最多一个具有非静态数据成员的基类,或者没有基类 具有非静态数据成员的类。

  • 它的基类(如果有的话)本身也是一个标准布局类。

  • 并且,没有与其第一个非静态类型相同的基类 数据成员。

在您的示例中,类 C 与第三条规则不匹配,因此 它不是标准布局类

此外,关于您关于“或”的问题,它仅适用于第二部分,即在“或”之后,该语句仍然是关于标准布局类对象的,但没有非静态成员。

【讨论】:

  • 我看过 cppref ,这仅适用于 C++14 之前的版本
  • 现在是 “所有非静态数据成员和位域都在同一个类中声明(全部在派生类中或全部在某个基类中)”
猜你喜欢
  • 2011-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-16
  • 2013-09-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多