明显的UB
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
在编译器的当前实现方法中,显然至少存在Vtable和b中包含垃圾值的值不一致的问题.所以在这些条件下,标准没有定义一个downcast的行为是有道理的.
不太明显的天真的情况
但是我很好奇知道在具体情况下是否有这样的规定呢?
例如:
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 ?
在这里我们可以很容易地想象编译器做正确的事情.但从标准的角度来看,还不清楚?
编辑:static_cast是用于说明目的的随机选择,如果与其他演员一起工作也很有意思!
解决方法
显然,正如其他答案所说,这是未定义的行为,如标准中所述.但是,如果您的Base类具有标准布局,并且DerivedForInt类不添加新数据成员,则它将具有相同的(标准)布局.
在这些条件下,即使是UB,你的演员也不应该出现任何麻烦.据其中一个消息来源,至少可以做到安全
DerivedForInt *derived = reinterpret_cast<DerivedForInt*>(&base.a);
资料来源:
What are Aggregates and PODs and how/why are they special?
PODs and inheritance in C++11. Does the address of the struct == address of the first member?
从第二个链接:
Here’s the definition,from the standard section 9 [class]:
A standard-layout class is a class that:
- has no non-static data members of type non-standard-layout class (or array of such types) or reference,
- has no virtual functions (10.3) and no virtual base classes (10.1),
- has the same access control (Clause 11) for all non-static data members,
- has no non-standard-layout base classes,
- either has no non-static data members in the most derived class and at most one base class with non-static data members,or has no base classes with non-static data members,and
- has no base classes of the same type as the first non-static data member.
然后保证您想要的属性(第9.2节[class.mem]):A pointer to a standard-layout struct object,suitably converted using a reinterpret_cast,points to its initial member (or if that member is a bit-field,then to the unit in which it resides) and vice versa.