错误的演员表 - 是演员表或使用未定义的行为

时间:2018-04-23 12:33:23

标签: c++ casting language-lawyer undefined-behavior

如果我从Base转换为Derived类型,但Base类型不是派生类型的实例,但只使用结果,是否会得到未定义的行为?

很难理解我在问什么?看一下这个例子:

struct Animal { int GetType(){...} };
struct Dog : Animal { bool HasLoudBark(){...}};
struct Cat : Animal { bool HasEvilStare(){...} };

Animal * a = ...;
Dog* d = static_cast<Dog*>(a);

if(a->GetType() == DogType && d->HasLoudBark())
    ....

在这种情况下,a可能是Dog,也可能不是static_cast。我们总是a Dog * dd,但除非我们确定Dog,否则我们永远不会使用a

假设Dog不是d,那么在演员阵容中这个未定义的行为是什么?或者它定义为我们实际上不使用Dog,除非它真的是 Sub S Dim ws as worksheet For each ws in worksheets ws.calculate 'or call your recalc routine ws.printout next ws end sub

赞赏参考标准的相关部分。

(是的,我知道我可以使用dynamic_cast和RTTI,可能这不是很好的代码,但我对这是否有效更感兴趣)

2 个答案:

答案 0 :(得分:36)

演员本身有不确定的行为。引用C ++ 17(n4659)[expr.static.cast] 8.2.10 / 11:

  

类型为“指向 cv1 B的指针”的prvalue,其中B是类类型,可以转换为类型为“指针”的prvalue   到 cv2 D“,其中DB派生的类(第13条),如果 cv2 是相同的cv - 资格为或更高   cv-qualification, cv1 。 ......如果是prvalue   键入“指向 cv1 B的指针”指向B,它实际上是D类型对象的子对象,结果指针   指向D类型的封闭对象。否则,行为未定义。

答案 1 :(得分:12)

This is undefined behaviour,但(足够有趣)如果您使用static_cast而不是cv T,则会将该恶魔赶走。

  

[expr.reinterpret.cast]/7

     

可以将对象指针显式转换为不同类型的对象指针。当对象指针类型的prvalue v转换为对象指针类型“指向static_­cast<cv T*>(static_­cast<cv void*>(v))的指针”时,结果为static_cast<void*>(d) == static_cast<void*>(a)

正如用户Angew所说,这个&#34;需要一个特定的内部表示,以确保a == d&#34;时的[class.mem]/22

这由26表示为GetType()

  

[class.mem]/26

     

如果标准布局类对象具有任何非静态数据成员,则其地址与其第一个非静态数据成员的地址相同(如果该成员不是位字段)。它的地址也与每个基类子对象的地址相同。

因此,如果Animal的{​​{1}}返回Animal Dog/queue的非静态数据成员的值,则会定义行为

在处理简单继承和默认对齐的对象时,会满足这些要求。