Ad *_*d N 9 c++ casting undefined-behavior
在一般情况下,从(动态)下降Base到其中一个派生类是(非常应得的)未定义行为Derived
class Base
{
public:
virtual void foo()
{ /* does something */ }
int a;
}
class Derived : public Base
{
public:
virtual void foo()
{ /* does something different */ }
double b;
}
Base obj;
Derived derObj = *static_cast<Derived *>(&obj); // <- here come the demons
Run Code Online (Sandbox Code Playgroud)
在目前的编译器实现方法中,这里显然至少存在Vtable和b中包含垃圾值的值不一致的问题.因此,在这些条件下,标准没有定义向下转换的行为是有道理的.
然而,我很想知道在特定情况下这条规则是否有一些让步? 举个例子:
class Base
{
public:
void foo()
{ /* does something */ }
int a = 1;
double b = 2.;
}
class DerivedForInt : public Base
{
int getVal()
{ return a }
}
Base obj;
DerivedForInt derObj = *static_cast<DerivedForInt *>(&obj); // <- still an UB ?
Run Code Online (Sandbox Code Playgroud)
在这里,我们可以很容易地想象编译器做正确的事 但从标准的角度来看,它仍未定义吗?
编辑:static_cast是一个随机选择,用于插图目的,如果与其他演员一起工作也很有趣!
好的,我可能会因为这个答案而被切成碎片......
显然,正如其他答案所述,这是未定义的行为,如标准中所见.但是,如果您的Base类具有标准布局,并且您的DerivedForInt类不添加新数据成员,则它将具有相同(标准)布局.
在这些情况下,即使是UB,你的阵容也不应该造成任何麻烦.根据其中一位消息来源,做一个至少是安全的
DerivedForInt *derived = reinterpret_cast<DerivedForInt*>(&base.a);
Run Code Online (Sandbox Code Playgroud)
资料来源:
P ++中的POD和继承11.结构的地址=第一个成员的地址吗?
从第二个链接:
这是定义,来自标准第9节[类]:
标准布局类是一个类:
- 没有非标准布局类(或此类类型的数组)或引用类型的非静态数据成员,
- 没有虚函数(10.3),也没有虚基类(10.1),
- 对所有非静态数据成员具有相同的访问控制(第11条),
- 没有非标准布局基类,
- 或者在最派生类中没有非静态数据成员,并且最多只有一个具有非静态数据成员的基类,或者没有具有非静态数据成员的基类,并且
- 没有与第一个非静态数据成员相同类型的基类.
然后保证你想要的财产(第9.2节[class.mem]):
指向标准布局结构对象的指针,使用reinterpret_cast进行适当转换,指向其初始成员(或者如果该成员是位字段,则指向它所在的单元),反之亦然.
这实际上比旧的要求更好,因为通过添加非平凡的构造函数和/或析构函数不会丢失reinterpret_cast的能力.