dynamic_cast失败 - 具体取决于操作系统版本

dynamic_cast fails - depending on OS Version

本文关键字:取决于 操作系统 版本 cast 失败 dynamic      更新时间:2023-10-16

我有一个动态转换失败。类布局是这样的:

class A1
{
    public:
virtual int foo1()=0;
};
class A2
{
    public:
    virtual int foo2();
};
class A3
{
public:
   virtual int foo3();
};
class B : public A1, public A2, public A3 
{
   int bar();
};

现在我使用指针(所以不会发生切片)进行向下投射。

main()
{
   B b;
   A1* a1 = dynamic_cast<A1*> (&b); // ok
   B*  b1 = dynamic_cast<B*>  (a1); // ok
   A2* a2_1 = dynamic_cast<A2*> (a1); // OSX 10.7 ok, OSX 10.9 fail
   A2* a1_2 = dynamic_cast<A2*> (b1); // ok
};
向下投射有效,

向上投射有效,但侧播并不总是有效。在OSX 10.7下,侧播可以工作,在OSX 10.9下则不能(GCC 4.2使用动态c ++ stdlib)。使用 gdb 查看 vtable,我可以清楚地看到列出的 A2 方法和成员。

我的问题:

a) 侧播在技术上是否正确?它应该工作还是这是一个运行时错误?
b) 如果侧播依赖于运行时,那么这个运行时在哪里定义?我一直认为这是二进制文件的一部分?
c) 故障dynamic_cast是什么样的(在查看组装时),您如何追踪此类问题?

更新:这是我在系统控制台中看到的

15-11-01 14:16:27,435 APPNAMECHANGED[15280]:dynamic_cast错误 1:以下两个type_info都应该具有公开可见性。 其中至少有一个是隐藏的。10A1, 15A2.

所以 c) 得到了回答,至少对于 OSX 10.9。看看控制台。(Linux,有人吗?这看起来像是关于符号可见性的问题。医生说(gcc.gnu.org/wiki/Visibility)

然而,这不是故事的全部 - 它变得更加困难。默认情况下,符号可见性是"默认的",但如果链接器只遇到一个隐藏的定义 - 只有一个 - 该 typeinfo 符号将永久隐藏(请记住C++标准的 ODR - 一个定义规则)。这适用于所有符号,但更有可能影响您的类型信息;没有 vtable 的类的 typeinfo 符号是按需在使用类进行 EH 的每个对象文件中定义的,并且定义较弱,因此定义在链接时合并到一个副本中。

这就引出了下一个问题,

d) 我们如何追踪哪个符号至少被标记为隐藏一次,以及在哪里以及为什么?有没有检查 .o 文件的工具?

我们发现可执行文件链接到一个 dylib 之后,这个问题终于解决了,dylib 本身与 c++ 运行时静态链接,但使用不同的编译器(gcc 4.8 vs clang)编译。

免责声明:我只回答问题 a)。

首先,根据 [class.virtual]/1,B 显然是一个多态类型,因为它继承了一个虚函数(准确地说,B继承了三个不同的函数)。
现在考虑 [expr.dynamic.cast]/8:

如果 CT指向或引用的类类型,则运行时 检查逻辑执行如下:

  • 如果,在派生最多的对象中,v指向(引用)到一个公共基类 C对象的子对象,如果只有一个类型 C 的对象派生自指向(引用)的子对象 通过v结果指向(引用)该C对象。
  • 否则,如果v指向(引用)派生最多的对象的公共基类子对象,以及派生最多的对象的类型 有一个基类,类型 C ,它是明确和公共的, 结果点(引用)到派生最多的子对象的C子对象 对象。
  • 否则,运行时检查将失败

所以是的,它应该有效。