通过void*强制转换为基

Casting to base via void*

本文关键字:转换 void 通过      更新时间:2023-10-16

这是未定义行为吗?

class Derived: public Base //No other bases!!!
{
//...
};
Derived d;
void *pv = &d;
Base *b = static_cast<Base*>(pv);
b->SomeMethod();

在合理的实现中,只要存在单继承,BaseDerived指针的位就会匹配。但是语言能保证这一点吗?

编辑:真正的目的是通过C层将指向多态c++对象的指针传递回c++回调。该对象创建为Derived,但在上述回调中作为Base使用。

,你所做的实际上调用未定义行为


标准要求保证从T*void*再铸回T*是安全的,后者的T*将保持与原来的T*相同的值。

5.29 静态强制转换 [expr.static.cast]

<一口> 13 <子>…对象指针类型的值转换为"指向cvvoid的指针"并返回,可能具有不同的cv-限定条件,应保持其原始值。"。

上述行为保证T * p = static_cast<T*> (static_cast<void*> (some_T_ptr))将在p中产生一个值,使得p == some_p .


在你的例子中,我们从void*转换到与原始T相关的类型,但它不是完全相同的T;这意味着操作的结果是未指定的。

编译器可以安全地假设void*指针(pv)中的地址最初指向Base,因此它不会做任何偏移修改来适当地调整我们从Derived*Base*,而不是从Base*Base*

编译器可以简单地将pv的值复制到b中,当它真正应该调整这个值时,因为它来自Derived的地址。

Derived * pd = &some_derived;
void    * pv = static_cast<void*> (pd);
Base    * pb = static_cast<Base*> (pv); // unsafe

关于

在合理的实现中,只要存在单继承,基指针和派生指针的位就应该匹配。”

对于简单类型是,但是当基是非多态且派生引入了虚成员时。

因此,将Derived*转换为void*,然后直接转换为Base*是未定义行为,不仅在形式上是学院式的,而且在实践中也是如此。


如果p的静态已知类型是指向多态对象的指针,那么特殊类型转换dynamic_cast<void*>( p )将给您一个指向最派生对象的指针。

这对于使用像std::unordered_map这样的哈希表是很有用的。


此外,可能与您的实际目的有关,该标准保证指向POD类型的第一个成员的指针可以被强制转换为指向该类型的指针,反之亦然。