我知道,类似的问题已经得到了回答,但有些事情仍然困扰着我。这里的示例自然是简化的,并且从真实的代码库中删除了与不相关的内容摘录。
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
是垃圾。由于X
和Y
具有相同的布局,因此在调试时,我会看到z1
在对象的X部分中具有Y值。我期望,因为我创建了对象为Z,这应该是正确的。相反,z2
似乎是正确的。
顺便说一下 - 类没有共同的祖先,这不是虚拟继承。
为什么呢?我在这里缺少什么?
编辑:
我一直缺少的很简单,我应该把头撞到墙上。简而言之:X
和Y
使用this
初始化其构造函数中的用户数据,所以当我认为Y
时,我确实正在向Z
传递指针{ {1}} ...
我将接受@ user2079303的答案,因为它让我再检查一次代码三次来发现这个......
答案 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);
}
为什么呢?我在这里缺少什么?
可能未定义的行为已经覆盖了你的记忆。