在具有共同祖先的类上的指针之间进行转换是否合法?编译器是否注意到这种层次结构并确保其安全(调用 1)?或者用户是否必须手动遍历层次结构才能始终安全(调用 2)?
说我们有
class A{};
class B:A{};
class C:A
{
public:
int SomeFunc(){return 3;}
};
int _tmain(int argc, _TCHAR* argv[])
{
B* b = (B*)((A*)new C()); // this is done manually, i believe it is safe
((C*)b)->SomeFunc(); // is this safe? this is the cast in question
return ((C*)((A*)b))->SomeFunc(); // this is done manually, i believe it is safe
}
Run Code Online (Sandbox Code Playgroud)
编辑:使该代码可编译且可运行
edit2:添加了更多评论
B* b = (B*)((A*)new C()); // this is done manually, i believe it is safe\nRun Code Online (Sandbox Code Playgroud)\n\n这不安全。\n粗略地说, expr
形式的强制转换被转换为or 。[expr.cast]/4:(T) static_castreinterpret_cast
\n\n\n执行的转换
\n\n\n
\n\n- ( 5.2.11
\nconst_cast),- (
\nstatic_cast5.2.9),- 一个
\nstatic_cast后接一个const_cast,- a
\nreinterpret_cast(5.2.10),或- 一个
\nreinterpret_cast后接一个const_cast,可以使用显式类型转换的强制转换表示法来执行。\n 相同的语义限制和行为适用[\xe2\x80\xa6]
\n
如果可以用上面列出的\n 多种方式解释\n 转换,则使用列表中第一个出现的解释,即使该解释产生的强制转换格式不正确。
您可以忽略const_cast这里,因为您的代码中没有完成任何限定转换。\nstatic_cast两种转换都足够,第一个转换为 ,(A*)第二个转换为 。(B*)\n第一个转换就很好。升级从来都不是问题。
\n第二个会引发未定义的行为。[expr.static.cast]/11:
\n\n\n类型为 \xe2\x80\x9c 的纯右值,指向cv1
\nB,\xe2\x80\x9d ,其中B是类类型,\n 可以转换为类型为 \xe2\x80\x9c 的纯右值,指向cv2D\xe2\x80\x9d,其中\nD是从 派生的类(第 10 条)B,如果存在从 \xe2\x80\x9cpointer 到D\xe2\x80\x9d 到 \xe2\x80\x9cpointer 到B\xe2\x80\x9d 的有效标准\n 转换( 4.10),\n cv2 与 cv1具有相同的 cv 限定,或比cv1更高的 cv 限定,并且B既不是 的虚拟基类D,也不是 的虚拟基类的基类D。[\xe2\x80\xa6]如果\n \xe2\x80\x9c 类型的纯右值指向 cv1 B\xe2\x80\x9d 指向的 aB实际上是类型 的\n 对象的子对象D,则结果指针指向到类型的封闭\n对象D。否则,转换的结果是未定义的。
另请注意,仅仅因为static_cast触发 UB 并不意味着它未被选中(并被替换为reinterpret_cast)。
第二个和第三个强制转换基于第一个强制转换(这会导致未定义的行为),因此谈论它们的有效性是没有意义的。
\n