将多重继承的对象转换为void *

时间:2014-05-22 08:20:16

标签: c++ casting multiple-inheritance

我知道,类似的问题已经得到了回答,但有些事情仍然困扰着我。这里的示例自然是简化的,并且从真实的代码库中删除了与不相关的内容摘录。

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初始化其构造函数中的用户数据,所以当我认为Y时,我确实正在向Z传递指针{ {1}} ...

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

2 个答案:

答案 0 :(得分:1)

既然你在谈论“C接口”,你是在单独编译一个库和一个接口吗?如果是这样,请确保两者都使用相同的编译器设置,即调试/释放模式,安全迭代器开/关等。

因为对象布局可能因编译器标志而异。

答案 1 :(得分:0)

z1的转换是正确的,并保证符合标准。以下是cppreference关于static_cast的引用。

  

可以将指向void(可能是cv-qualified)的类型指针的prvalue转换为指向任何类型的指针。将指向[sic]的任何指针转换为void并返回指向原始(或更多cv限定)类型的指针,保留其原始值。

This示例顺利运行。

#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);
}
  

为什么呢?我在这里缺少什么?

可能未定义的行为已经覆盖了你的记忆。