C++ 将多个继承对象强制转换为void或从void转换为继承对象*

C++ 将多个继承对象强制转换为void或从void转换为继承对象*,c++,casting,multiple-inheritance,C++,Casting,Multiple Inheritance,我知道,类似的问题已经得到了回答,但仍有一些问题困扰着我。这里的示例自然地被简化,并从真实代码库中的不相关内容摘录中剥离出来 class X {...}; class Y {...}; class Z : public X, public Y {...} 现在我创建Z对象并将其通过C接口(如void*) 在一些回调中,我得到了我的对象(仍然是void*) void回调(void*数据) { Z*z1=静态_-cast(数据); Z*z2=动态(静态)广播(数据); } z1是垃圾。由于X和Y

我知道,类似的问题已经得到了回答,但仍有一些问题困扰着我。这里的示例自然地被简化,并从真实代码库中的不相关内容摘录中剥离出来

class X {...};
class Y {...};
class Z : public X, public Y {...}
现在我创建Z对象并将其通过C接口(如
void*

在一些回调中,我得到了我的对象(仍然是
void*

void回调(void*数据)
{
Z*z1=静态_-cast(数据);
Z*z2=动态(静态)广播(数据);
}
z1
是垃圾。由于
X
Y
具有相同的布局,因此在调试时,我看到
z1
在对象的X部分具有Y的值。我想,既然我把对象创建为Z,那应该是正确的。相反,
z2
似乎是正确的

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

为什么??我错过了什么


编辑: 我错过的很简单,我应该为此把头撞在墙上。长话短说:
X
Y
使用
this
初始化其构造函数中的用户数据,因此我实际上是在传递一个指向
Y
的指针,而我认为它是
Z


我将接受@user207933的答案,因为它让我再次检查代码三次,以发现这一点……

z1的转换是正确的,并保证按照标准工作。下面是一段关于
static\u cast
的引用

指针指向void(可能是cv限定)类型的prvalue可以转换为指向任何类型的指针。将指向指针[sic]的任何指针转换为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);
}
#包括
结构X{
INTA;
};
结构{
int b;
};
结构Z:公共X,公共Y{
INTC;
};
void回调(void*数据){
Z*z1=静态_-cast(数据);
断言(z1->a==1);
断言(z1->b==2);
断言(z1->c==3);
}
int main(){
Z Z;
z、 a=1;
z、 b=2;
z、 c=3;
回调((void*)&z);
}
为什么??我错过了什么


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

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


因为对象布局可能因编译器标志的不同而不同。

您能发布一个新的吗?第一次强制转换是正确的,它应该会起作用。在有人抱怨之前,您可能希望编辑掉淫秽内容。
static\u cast
to和from
void*
对于类指针来说是安全的(我想这是在标准的某个地方指定的)。你可能遇到了内存损坏。你说的“胡说八道”是什么意思?错误的,不正确的,垃圾?只要不引起歧义,我不介意骂人。准确地展示你所观察到的东西会更有意义。也许编译器可以自由选择它对父成员的排序顺序,并将
Y
X
作为
Z
的内存布局。在您发布的代码中:
z1
是正确的,
z2
是未定义的行为。要解释这一点与您的观察结果之间的差异,只能通过发布一个完整的程序来解决。关于您没有向我们展示的代码可能会如何影响这一点,有太多的可能性要列出。如果他只是在创建对象时检查同一文件中的对象,这将不是问题。
void*
可以通过对对象一无所知的其他代码。当然,我们不能仅仅根据目前发布的内容来确定。是的,C部分只是将指针传输回我的回调,它甚至在同一个翻译单元(*.cpp文件)中。调试器只确认有什么地方出错。我得到的是一个带有“无效访问”错误的崩溃,因为它达到了一些随机值。@Jakub:好的,在这种情况下,我将在回答中消除对调试器是否正常的怀疑。你可能应该在你的问题中提到崩溃。你让我再次在我的代码中产生怀疑,这是一件好事。我发现了问题(请参见编辑)。谢谢
void callback(void* data)
{
    Z* z1 = static_cast<Z*>(data);
    Z* z2 = dynamic_cast<Z*>(static_cast<Y*>(data));
}
#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);
}