C++ C型铸造导致SIGILL,动态_铸造正常

C++ C型铸造导致SIGILL,动态_铸造正常,c++,g++,C++,G++,在我的一个项目中,我有一个实现四个接口的类: class A : public B, public C, public D, public E { ----Implementation Code here---- }; 这四个接口只包含纯虚拟函数,没有一个构成菱形问题(因此我不需要使用virtual关键字),因此我在执行类似操作时没有发现任何问题: A* var = new A; ((C*)var)->method_from

在我的一个项目中,我有一个实现四个接口的类:

class A : public B,
          public C,
          public D,
          public E
{
  ----Implementation Code here----
};
这四个接口只包含纯虚拟函数,没有一个构成菱形问题(因此我不需要使用virtual关键字),因此我在执行类似操作时没有发现任何问题:

A* var = new A;
((C*)var)->method_from_interface();
然而,一些丑陋的事情正在发生,因为函数正在跳转到一个类的不同方法,valgrind抱怨未处理的指令。然而,这样做:

 A* var = new A;
(dynamic_cast<C*>(var))->method_from_interface();

注意,我知道在这段时间里,D*实际上是A*,所以对B*进行A转换并没有违反任何规则。虽然我不能静态转换它,因为D*和B*没有关系,但我可以成功地使用reinterpret\u cast。

C样式转换只是对指向类的指针进行“基本”内存映射。如果您的方法在类中是offset=42,则会使(*(A+42))()(当然是简化的)

但是,如果从多个类继承,则必须考虑不同的类以及编译器放置它们的顺序

静态_cast考虑了多重继承

在您的示例中,它可能与B、C、D或E一起使用,但与其他的不一起使用。但是,您没有充分的理由这样做:您将调用
A->methodFromInterface()
,它就可以工作了

在C++上,建议使用静态的CAST或动态的CAST(注意:第二个依赖于RTTI,可能不可用),丢弃旧的C型CAST。 编辑 试图复制问题,但无法,可以在上找到文件

  • 类别2.hpp:
  • class2.cpp:
  • class.cpp:
在MacOs 10.6上编译:

g++ -fno-rtti -o truc ./class.cpp ./class2.cpp && ./truc

C-style cast只是对指向类的指针进行“基本”内存映射。如果您的方法在类中是offset=42,则会使(*(A+42))()(当然是简化的)

但是,如果从多个类继承,则必须考虑不同的类以及编译器放置它们的顺序

静态_cast考虑了多重继承

在您的示例中,它可能与B、C、D或E一起使用,但与其他的不一起使用。但是,您没有充分的理由这样做:您将调用
A->methodFromInterface()
,它就可以工作了

在C++上,建议使用静态的CAST或动态的CAST(注意:第二个依赖于RTTI,可能不可用),丢弃旧的C型CAST。 编辑 试图复制问题,但无法,可以在上找到文件

  • 类别2.hpp:
  • class2.cpp:
  • class.cpp:
在MacOs 10.6上编译:

g++ -fno-rtti -o truc ./class.cpp ./class2.cpp && ./truc

问题在于你的职能是做些什么

这行很好:

D* iface = p->recoverItemByName("nameThatReturnsClassA");
但这条线是坏的,因为B和D无关,所以你不能安全施放。尝试调用static_cast(iface),您将看到编译器在抱怨-这应该是一个警告

((B*) iface)->call_method_from_b_iface(); 
在上一行中,您正在编写iface不仅指向D,而且指向a的知识。最好将a指针存储到a并使用该指针。我也是

A* iface = p->recoverItemByName("nameThatReturnsClassA");
iface->call_method_from_b_iface(); 
如果您仍然想坚持使用D*iface,那么可以这样编写代码(两个选项中只有一个选项):

D*iface=p->recoverItemByName(“namethatturnsclassa”);
静态投影


<>最后但并非最不重要:尽量避免旧的C风格的演员阵容,总是尝试使用C++风格的CaskStupe,StistaCase/DyrimCyCaseand RealTytPraseCask(按这个顺序)。 这行很好:

D* iface = p->recoverItemByName("nameThatReturnsClassA");
但这条线是坏的,因为B和D无关,所以你不能安全施放。尝试调用static_cast(iface),您将看到编译器在抱怨-这应该是一个警告

((B*) iface)->call_method_from_b_iface(); 
在上一行中,您正在编写iface不仅指向D,而且指向a的知识。最好将a指针存储到a并使用该指针。我也是

A* iface = p->recoverItemByName("nameThatReturnsClassA");
iface->call_method_from_b_iface(); 
如果您仍然想坚持使用D*iface,那么可以这样编写代码(两个选项中只有一个选项):

D*iface=p->recoverItemByName(“namethatturnsclassa”);
静态投影

最后但并非最不重要:尽量避免旧的C风格的演员阵容,总是尝试使用C++风格的演员StaskSCAST,StistaCype/DyrimCype演员和RealTurkType演员(按这个顺序)。 注意,我知道在这个时候,D*实际上是A*,所以 对B*进行选角并没有违反任何规则

您可能知道它实际上是一个A*,但编译器不知道,至少在编译时,当它试图找出要发出什么代码来进行转换时是这样

当您使用虚拟方法从多个类继承时,会发生一件有趣的事情。当您从派生类转换为某个接口类时,指针地址将发生更改!编译器对指针进行调整,使其对您声明的指针类型有效。你自己试试,从一个
A*
指针开始显示它的值,然后转换到A
B*
C*
,和
D*
并显示它们。最多一个基类与
A*
相同,其他基类则不同

当您使用C样式转换时,您告诉编译器“我不管您是否能正确地进行转换,无论如何都要这样做。”它会将
D*
适当地视为
B*
,而不进行所需的修正,因此现在指针完全错了。它没有指向类B vtable,因此调用了错误的方法

动态_cast之所以有效,是因为它使用了运行时可用的额外信息;它可以将指针跟踪到其最派生的
A*
,然后返回到A
B*

注意,我知道在这个时候,D*实际上是A*,所以 对B*进行选角并没有违反任何规则

您可能知道它实际上是一个A*,但编译器不知道,至少在编译时,当它试图找出要发出什么代码来进行转换时是这样

A