从指向派生 class 的指针的 `static_cast<Base*>(static_cast<void*>(derived)) 什么时候有效?
When is a `static_cast<Base*>(static_cast<void*>(derived))` from a pointer to a derived class valid?
本题不涉及多态,即不涉及虚方法,不涉及虚基classes。以防万一,我的案子不涉及这些。
假设我有一个 class Derived
,它有一个 Base
类型的明确可访问 parent,没有多态性(没有虚方法,没有虚基 classes),但可能涉及间接 and/or 多重继承。
进一步假设我有一个有效的指针 Derived *derived
(指向类型 Derived
的 object 或其子 class)。
在这种情况下,我相信 static_cast<Base*>(derived)
是有效的
(导致有效的可用指针)。当 Base
和 Derived
之间的祖先链涉及多重继承时,此 static_cast
可能意味着指针调整以在 Derived
实例中定位 Base
实例。为此,编译器需要知道继承链,他在本例中就是这样做的。但是,如果插入到 void *
的中间转换,则该继承链信息对编译器是隐藏的。对于哪个继承链,这样的静态转换仍然有效?我期望以下之一:
- None 有吗?从 void 指针访问
static_cast
是未定义的行为,除非指针确实指向确切的类型。
- 对于没有multiple-inheritance的所有链?然后,编译器可以保证
Base
总是在 Derived
的开头——但是标准是怎么说的?
- 对于在所有中间多重继承链的第一个 parent class 中找到
Base
的所有链?也许 Base
和 Derived
的开头仍然匹配?
- 总是?
static_cast
到 void 指针总是可以调整到第一个 parent 的开始,而 static_cast
从 void 指针撤消该调整。但是对于多重继承,"very first parent" 不一定是所有 parent 的 parent。
static_cast<Base*>(static_cast<void*>(derived))
在 C++ 标准中有一个名称。它被称为 reinterpret_cast
。它在 [expr.reinterpret.cast] paragraph 7:
中指定
An object pointer can be explicitly converted to an object pointer of a different type. When a prvalue v of object pointer type is converted to the object pointer type “pointer to cv T”, the result is static_cast<cv T*>(static_cast<cv void*>(v))
. [ Note: Converting a prvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer value. — end note ]
A reinterpret_cast
是我们告诉编译器将指针视为其他东西。编译器无法或将根据此指令进行任何调整。如果我们撒谎,那么行为就是未定义的。标准是否说明这样的 reinterpret_cast
何时有效?它确实如此。 [basic.compound] paragraph 4:
中定义了指针互换性的概念
Two objects a and b are pointer-interconvertible if:
- they are the same object, or
- one is a union object and the other is a non-static data member of that object ([class.union]), or
- one is a standard-layout class object and the other is the first non-static data member of that object, or, if the object has no
non-static data members, any base class subobject of that object
([class.mem]), or
- there exists an object c such that a and c are pointer-interconvertible, and c and b are pointer-interconvertible.
If two objects are pointer-interconvertible, then they have the same
address, and it is possible to obtain a pointer to one from a pointer
to the other via a reinterpret_cast
. [ Note: An array object and its
first element are not pointer-interconvertible, even though they have
the same address. — end note ]
第三个项目符号就是你的答案。 class 层次结构中的对象必须遵守限制(standard layout 从顶层到最派生),只有这样才能保证转换给出明确定义的结果。
本题不涉及多态,即不涉及虚方法,不涉及虚基classes。以防万一,我的案子不涉及这些。
假设我有一个 class Derived
,它有一个 Base
类型的明确可访问 parent,没有多态性(没有虚方法,没有虚基 classes),但可能涉及间接 and/or 多重继承。
进一步假设我有一个有效的指针 Derived *derived
(指向类型 Derived
的 object 或其子 class)。
在这种情况下,我相信 static_cast<Base*>(derived)
是有效的
(导致有效的可用指针)。当 Base
和 Derived
之间的祖先链涉及多重继承时,此 static_cast
可能意味着指针调整以在 Derived
实例中定位 Base
实例。为此,编译器需要知道继承链,他在本例中就是这样做的。但是,如果插入到 void *
的中间转换,则该继承链信息对编译器是隐藏的。对于哪个继承链,这样的静态转换仍然有效?我期望以下之一:
- None 有吗?从 void 指针访问
static_cast
是未定义的行为,除非指针确实指向确切的类型。 - 对于没有multiple-inheritance的所有链?然后,编译器可以保证
Base
总是在Derived
的开头——但是标准是怎么说的? - 对于在所有中间多重继承链的第一个 parent class 中找到
Base
的所有链?也许Base
和Derived
的开头仍然匹配? - 总是?
static_cast
到 void 指针总是可以调整到第一个 parent 的开始,而static_cast
从 void 指针撤消该调整。但是对于多重继承,"very first parent" 不一定是所有 parent 的 parent。
static_cast<Base*>(static_cast<void*>(derived))
在 C++ 标准中有一个名称。它被称为 reinterpret_cast
。它在 [expr.reinterpret.cast] paragraph 7:
An object pointer can be explicitly converted to an object pointer of a different type. When a prvalue v of object pointer type is converted to the object pointer type “pointer to cv T”, the result is
static_cast<cv T*>(static_cast<cv void*>(v))
. [ Note: Converting a prvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer value. — end note ]
A reinterpret_cast
是我们告诉编译器将指针视为其他东西。编译器无法或将根据此指令进行任何调整。如果我们撒谎,那么行为就是未定义的。标准是否说明这样的 reinterpret_cast
何时有效?它确实如此。 [basic.compound] paragraph 4:
Two objects a and b are pointer-interconvertible if:
- they are the same object, or
- one is a union object and the other is a non-static data member of that object ([class.union]), or
- one is a standard-layout class object and the other is the first non-static data member of that object, or, if the object has no non-static data members, any base class subobject of that object ([class.mem]), or
- there exists an object c such that a and c are pointer-interconvertible, and c and b are pointer-interconvertible.
If two objects are pointer-interconvertible, then they have the same address, and it is possible to obtain a pointer to one from a pointer to the other via a
reinterpret_cast
. [ Note: An array object and its first element are not pointer-interconvertible, even though they have the same address. — end note ]
第三个项目符号就是你的答案。 class 层次结构中的对象必须遵守限制(standard layout 从顶层到最派生),只有这样才能保证转换给出明确定义的结果。