对于此问题,不应涉及多态性,即不涉及虚拟方法,不涉及虚拟基类。以防万一,我的案子不涉及其中任何一个。
假设我有一个类Derived
,它具有类型Base
的可访问父对象,没有多态性(没有虚拟方法,没有虚拟基类),但是可能涉及间接和/或多重继承。
进一步假设我有一个有效的指针Derived *derived
(指向Derived
类型的对象或其子类)。
在这种情况下,我认为static_cast<Base*>(derived)
是有效的
(导致有效的可用指针)。当Base
和Derived
之间的祖先链涉及多重继承时,此static_cast
可能意味着指针调整,以在Base
实例中定位Derived
实例。为此,编译器需要知道继承链,在这种情况下,他需要这样做。但是,如果插入到void *
的中间转换,则继承链信息对编译器是隐藏的。但是,对于哪种继承链而言,这种静态强制转换仍然有效?我期望以下之一:
static_cast
是未定义的行为,除非指针真正指向确切的类型。Base
始终位于Derived
的开头-但是标准怎么说呢?Base
的所有链?也许Base
和Derived
的开头仍然匹配?static_cast
到void指针总是可以调整到第一个父对象的开始,而static_cast
可以从void指针撤消该调整。但是通过多重继承,“非常第一的父母”不一定是所有父母的父母。答案 0 :(得分:3)
static_cast<Base*>(static_cast<void*>(derived))
在C ++标准中具有名称。它称为reinterpret_cast
。在[expr.reinterpret.cast] paragraph 7中指定:
可以将对象指针显式转换为其他类型的对象指针。将对象指针类型的prvalue v转换为对象指针类型“ cv T的指针”时,结果为
static_cast<cv T*>(static_cast<cv void*>(v))
。 [注意:将类型为“指向T1的指针”的prvalue转换为“指向T2的指针”的类型(其中T1和T2是对象类型,并且T2的对齐要求不严格于T1的对齐要求)并返回其原始类型产生原始指针值。 —尾注]
reinterpret_cast
是我们告诉编译器将指针视为其他对象。在此指令下,编译器无法执行或将无法进行任何调整。如果我们撒谎,那么行为就根本是不确定的。标准是否说出这样的reinterpret_cast
有效?确实有。在[basic.compound] paragraph 4中定义了一个指针互转换的概念:
如果满足以下条件,则两个对象a和b是指针可互换的:
- 它们是同一个对象,或者
- 一个是联合对象,另一个是该对象的非静态数据成员([class.union]),或者
- 一个是标准布局类对象,另一个是该对象的第一个非静态数据成员,或者,如果该对象没有 非静态数据成员,该对象的任何基类子对象 ([class.mem]),或
- 存在一个对象c,使得a和c是指针可互换的,而c和b是指针可互换的。
如果两个对象是指针可互换的,则它们具有相同的 地址,并且有可能从指针获得指向一个的指针 通过
reinterpret_cast
到另一个。 [注意:数组对象及其 第一个元素不是指针可互换的,即使它们具有 相同的地址。 —尾注]
第三个项目符号就是您的答案。类层次结构中的对象必须遵守限制(从最上层到多数派生为standard layout),只有这样才能保证强制类型转换提供明确定义的结果。