指向派生类的指针的`static_cast <Base *>(static_cast <void *>(派生))何时有效?

时间:2019-08-24 10:08:14

标签: c++ inheritance static-cast upcasting

对于此问题,不应涉及多态性,即不涉及虚拟方法,不涉及虚拟基类。以防万一,我的案子不涉及其中任何一个。

假设我有一个类Derived,它具有类型Base的可访问父对象,没有多态性(没有虚拟方法,没有虚拟基类),但是可能涉及间接和/或多重继承。 进一步假设我有一个有效的指针Derived *derived (指向Derived类型的对象或其子类)。

在这种情况下,我认为static_cast<Base*>(derived)是有效的 (导致有效的可用指针)。当BaseDerived之间的祖先链涉及多重继承时,此static_cast可能意味着指针调整,以在Base实例中定位Derived实例。为此,编译器需要知道继承链,在这种情况下,他需要这样做。但是,如果插入到void *的中间转换,则继承链信息对编译器是隐藏的。但是,对于哪种继承链而言,这种静态强制转换仍然有效?我期望以下之一:

  • 什么都没有?从void指针访问static_cast是未定义的行为,除非指针真正指向确切的类型。
  • 对于没有多重继承的所有链?然后,编译器可以保证Base始终位于Derived的开头-但是标准怎么说呢?
  • 对于在所有中间多重继承链的第一个父类中找到Base的所有链?也许BaseDerived的开头仍然匹配?
  • 总是吗? static_cast到void指针总是可以调整到第一个父对象的开始,而static_cast可以从void指针撤消该调整。但是通过多重继承,“非常第一的父母”不一定是所有父母的父母。

1 个答案:

答案 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),只有这样才能保证强制类型转换提供明确定义的结果。