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

Mik*_*ine 36 c++ casting undefined-behavior language-lawyer

如果我从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())
    ....
Run Code Online (Sandbox Code Playgroud)

在这种情况下a可能或不是Dog.我们总是做static_castaDog * d,但我们从来不使用d,除非我们确定它的一个Dog.

假设a不是a Dog,那么在演员阵容中这个未定义的行为是什么?或者它被定义为我们实际上没有使用,d除非它真的是一个Dog

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

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

Rei*_*ica 36

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

类型为"指向cv1的 指针"的prvalue B,其中B是一个类类型,可以转换为类型为"指向cv2的 指针"的prvalue D,其中D是一个派生类(第13条)B,如果cv2是相同的cv-qualification,则或者比cv1更高的cv资格....如果"指向cv1的 指针B" 类型的prvalue指向B实际上是类型对象的子对象D,则生成的指针指向类型的封闭对象D.否则,行为未定义.

  • @Angew这也许可编译器认为UB不会发生.因此在示例代码中,编译器可以假设`a`指向`Dog`,并将`a-> getType()== DogType`优化为`true`. (5认同)
  • 如果我没弄错的话,用"reinterpret_cast"安全OP是对的,对吧? (3认同)
  • @MikeVine一旦程序在任何地方展示UB,标准就不会对其行为进行任何限制,甚至*在运行时首次达到UB构造之前.换句话说,如果某个程序有UB,则所有投注均已关闭. (3认同)
  • @ user1810087非常好笑.问题是"赞赏参考标准的相关部分." (2认同)

YSC*_*YSC 12

这是未定义的行为,但(足够有趣)如果你会使用reinterpret_cast而不是static_cast,你会把那个恶魔赶走.

[expr.reinterpret.cast]/7

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

正如用户Angew所指出的,这"需要特定的内部表示,以确保static_cast<void*>(d) == static_cast<void*>(a)何时a == d".

这表示[class.mem]/2226:

[class.mem]/26

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

因此,如果GetType()Animal返回一个非静态数据成员的从值公共初始序列AnimalDog,该行为被定义.

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