指向派生类的指针中的"static_cast<Base*>(static_cast<void*>(派生))"何时有效?
When is a `static_cast<Base*>(static_cast<void*>(derived))` from a pointer to a derived class valid?
对于这个问题,不涉及多态性,即没有虚拟方法,没有虚拟基类。以防万一,我的案子不涉及其中任何一个。
假设我有一个类Derived
,它有一个明确的可访问父级类型Base
,没有多态性(没有虚拟方法,没有虚拟基类(,但可能涉及间接和/或多重继承。 进一步假设我有一个有效的指针Derived *derived
(指向类型Derived
的对象或其子类(。
在这种情况下,我相信static_cast<Base*>(derived)
是有效的 (生成有效的可用指针(。当Base
和Derived
之间的祖先链涉及多重继承时,此static_cast
可能意味着指针调整以在Derived
实例中定位Base
实例。为此,编译器需要知道继承链,在这种情况下他就是这样做的。但是,如果插入了void *
的中间强制转换,则该继承链信息将对编译器隐藏。对于哪个继承链,这样的静态强制转换仍然有效?我期望以下其中一项:
- 完全没有?从 void 指针访问
static_cast
是未定义的行为,除非指针确实指向确切的类型。 - 对于所有没有多重继承的链?然后,编译器可以保证
Base
始终处于Derived
的开头 - 但是标准是什么? - 对于在所有中间多重继承链的第一个父类中找到
Base
的所有链?也许Base
和Derived
的开始仍然匹配? - 总是?
static_cast
void 指针始终可以调整到第一个父指针的开头,并且从 void 指针撤消该调整static_cast
。但是,对于多重继承,"第一父母"不一定是所有父母的父母。
static_cast<Base*>(static_cast<void*>(derived))
在C++标准中有一个名称。这被称为reinterpret_cast
。在[expr.reinterpret.cast]第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]第4段中定义了指针互转换性的概念:
在以下情况下,两个对象 a 和 b 是指针可相互转换的:
- 它们是同一对象,或者
- 一个是联合对象,另一个是该对象的非静态数据成员([class.union](,或者
- 一个是标准布局类对象,另一个是该对象的第一个非静态数据成员,或者,如果该对象没有 非静态数据成员,该对象的任何基类子对象 ([class.mem](,或
- 存在一个对象 C,使得 A 和 C 是指针可相互转换的,C 和 B 是指针可相互转换的。
如果两个对象是指针可相互转换的,则它们具有相同的 地址,并且可以从指针获取指向 1 的指针 通过
reinterpret_cast
到另一个。[ 注意:数组对象及其 第一个元素不是指针可相互转换的,即使它们具有 相同的地址。— 尾注 ]
第三个项目符号是你的答案。类层次结构中的对象必须遵守限制(从顶部基础到最派生的标准布局(,只有这样才能保证强制转换给出明确定义的结果。
- 为什么使用 "this" 指针调用派生成员函数?
- 具有奇怪重复模板模式的派生类中的成员变量已损坏
- 如何理解C++标准N3337中的expr.const.cast子句8
- 在派生函数中指定void*参数
- 如何通过派生类函数更改基类中的向量
- 如何委托派生类使用其父构造函数?
- C++Cast运算符过载
- 如何使用单独文件中的派生类访问友元函数对象
- 派生类销毁的最佳实践是什么
- 如何使用基类指针引用派生类成员
- 派生类是否可以在抽象工厂设计模式中具有数据成员
- 使用基类指针创建对象时,缺少派生类析构函数
- 如何引用基类的派生类?
- 存储模板类型以强制转换回派生<T>
- 需要从 istream 和 ostream 派生 iostream
- 在 C++ 中用派生类型重写成员函数
- 具有多个类、派生类的C++正向声明
- 有没有一种"cleaner"的方法可以在指向基的指针向量中找到派生类的第一个实例?
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 使用派生到基类的 boost 序列化"unregistered void cast"