将多继承对象转换为void*或从void*转换为多继承对象

Casting multiple-inherited object to and from void*

本文关键字:void 转换 继承 对象 或从      更新时间:2023-10-16

我知道,类似的问题已经有了答案,但我仍然有一些困惑。这里的示例自然地简化了,并从真实的代码库中剥离了不相关的内容。

class X {...};
class Y {...};
class Z : public X, public Y {...}

现在我创建Z对象,并把它通过C接口(作为void*)

Z* z = new Z();
doSomeWeirdStuff(z);

在一些回调,我得到我的对象回来(仍然作为void*)。

void callback(void* data)
{
    Z* z1 = static_cast<Z*>(data);
    Z* z2 = dynamic_cast<Z*>(static_cast<Y*>(data));
}

z1是垃圾。由于XY具有相同的布局,当我调试时,我看到z1在对象的X部分具有Y的值。我期望,因为我创建的对象是Z,这应该是正确的。而z2似乎是正确的。

顺便说一下,类没有共同的祖先,这不是虚拟继承。

为什么?我遗漏了什么?


编辑:我错过的东西很简单,我应该为此而自食其果。长话短说:XY使用this在它们的构造函数中初始化用户数据,所以当我认为它是Z时,我真的传递了一个指向Y的指针…

我要接受@user2079303的答案,因为它让我再检查三次代码来发现这个

既然你在谈论"C接口",你是在分别编译库和接口吗?如果是这样,请确保两者使用相同的编译器设置,即调试/发布模式,安全迭代器开/关等。

z1的转换是正确的,并保证按标准工作。以下是cppreference对static_cast的引用。

指向void(可能是cv限定的)类型指针的右值可以转换为指向任何类型的指针。将任何指针转换为void指针,再转换回指向原始(或更符合cv的)类型的指针,将保留其原始值。

这个例子运行正常。

#include <cassert>
struct X {
    int a;
};
struct Y {
    int b;
};
struct Z : public X, public Y {
    int c;
};
void callback(void* data) {
    Z* z1 = static_cast<Z*>(data);
    assert(z1->a == 1);
    assert(z1->b == 2);
    assert(z1->c == 3);
}
int main() {
    Z z;
    z.a = 1;
    z.b = 2;
    z.c = 3;
    callback((void*) &z);
}

为什么?我遗漏了什么?

可能未定义的行为已经覆盖了您的内存。