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_cast
的a
到Dog * 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的 指针"的prvalueD
,其中D
是一个派生类(第13条)B
,如果cv2是相同的cv-qualification,则或者比cv1更高的cv资格....如果"指向cv1的 指针B
" 类型的prvalue指向B
实际上是类型对象的子对象D
,则生成的指针指向类型的封闭对象D
.否则,行为未定义.
YSC*_*YSC 12
这是未定义的行为,但(足够有趣)如果你会使用reinterpret_cast
而不是static_cast
,你会把那个恶魔赶走.
可以将对象指针显式转换为不同类型的对象指针.当对象指针类型的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]/22
为26
:
如果标准布局类对象具有任何非静态数据成员,则其地址与其第一个非静态数据成员的地址相同(如果该成员不是位字段).它的地址也与每个基类子对象的地址相同.
因此,如果GetType()
的Animal
返回一个非静态数据成员的从值公共初始序列的Animal
和Dog
,该行为被定义.
处理简单继承和默认对齐对象时,满足这些要求.