bur*_*nck 1 c++ inheritance static-cast upcasting
对于这个问题,不涉及多态性,即不涉及虚方法,不涉及虚基类。以防万一,我的案子不涉及其中任何一个。
假设我有一个类Derived,它有一个明确的可访问父类型Base,没有多态性(没有虚拟方法,没有虚拟基类),但可能涉及间接和/或多继承。进一步假设我有一个有效的指针Derived *derived
(指向类型Derived或其子类的对象)。
在这种情况下,我相信static_cast<Base*>(derived)是有效的(产生有效的可用指针)。Base当和之间的祖先链Derived涉及多重继承时,这static_cast可能意味着指针调整以在实例Base内定位实例Derived。为此,编译器需要知道继承链,在本例中他就是这样做的。但是,如果插入了中间转换void *,则编译器将隐藏该继承链信息。对于哪个继承链来说,这样的静态转换仍然有效?我期望以下之一:
static_castfrom void 指针是未定义的行为,除非该指针确实指向确切的类型。Base始终位于Derived- 但标准怎么说?Base在所有中间多重继承链的第一个父类中可以找到什么?Base也许和的开始Derived仍然匹配?static_castto void 指针始终可以调整到第一个父级的开头,而static_castfrom void 指针则撤消该调整。但对于多重继承,“第一个父母”不一定是所有父母的父母。static_cast<Base*>(static_cast<void*>(derived))在 C++ 标准中有一个名称。它被称为reinterpret_cast. 它在[expr.reinterpret.cast] 第 7 段中指定:
\n\n\n对象指针可以显式转换为不同类型的对象指针。当对象指针类型的纯右值 v 转换为对象指针类型 \xe2\x80\x9cpointer to cv T\xe2\x80\x9d 时,结果为
\nstatic_\xc2\xadcast<cv T*>(static_\xc2\xadcast<cv void*>(v))。[ 注意:将 \xe2\x80\x9c 类型的指针到 T1\xe2\x80\x9d 的纯右值转换为 \xe2\x80\x9c 类型的指针到 T2\xe2\x80\x9d (其中 T1 和 T2 是对象类型,其中T2 的对齐要求并不比 T1 更严格),并且返回到其原始类型会产生原始指针值。\xe2\x80\x94 尾注]
Areinterpret_cast是我们告诉编译器将指针视为其他东西。编译器可以或不会根据该指令进行任何调整。如果我们撒谎了,那么这种行为就是不确定的。该标准是否规定了此类何时reinterpret_cast有效?事实上确实如此。[basic.compound] 第 4 段定义了指针互换性的概念:
\n\n\n两个对象 a 和 b 是指针可相互转换的,如果:
\n\n\n
\n\n- 它们是同一个对象,或者
\n- 一个是联合对象,另一个是该对象的非静态数据成员 ([class.union]),或者
\n- 一个是标准布局类对象,另一个是该对象的第一个非静态数据成员,或者,如果该对象没有\n 非静态数据成员,则为该对象的任何基类子对象\n ([class .mem]),或
\n- 存在一个对象 c,使得 a 和 c 是指针可相互转换的,并且 c 和 b 是指针可相互转换的。
\n如果两个对象是指针可相互转换的,那么它们具有相同的地址,并且可以通过
\nreinterpret_\xc2\xadcast. [ 注意:数组对象及其第一个元素不可进行指针互换,即使它们具有相同的地址。\xe2\x80\x94 尾注]
第三个项目符号就是你的答案。类层次结构中的对象必须遵守限制(从顶层到最派生的标准布局),只有这样才能保证强制转换提供明确定义的结果。
\n