【问题标题】:dynamic_cast in C++ doesn't work without having RTTI on; Why?如果不启用 RTTI,C++ 中的 dynamic_cast 将无法工作;为什么?
【发布时间】:2018-02-16 00:11:56
【问题描述】:

虚拟方法在没有 RTTI 的情况下也可以工作,这是否意味着在运行时有足够的数据来确定它是哪个类?

(我想知道如何向下转换,然后检查它是否是指向正确类型的指针。不过,我无法修改所涉及的类或打开 RTTI。)

【问题讨论】:

  • 虚拟函数被实现为一个函数指针表。那里没有类型信息。
  • @PaulRooney 在某种程度上有一些信息,但仅足以确定最派生的类型,不足以测试给定类型是否在类继承树中的任何位置。跨度>
  • 虚函数不使用 RTTI 但 dynamic_cast 使用?

标签: c++ casting rtti downcast


【解决方案1】:

类型信息,动态类型标识,虚函数调度不需要。

虚拟函数调度通常通过每个对象中的一个 vtable 指针来实现,其中该指针指向一个特定类型的函数实现指针表(“vtable”)。

dynamic_casttypeid 需要类型信息。


对于返回类型信息的typeid,该信息必须存在于可执行文件的某个位置。当您关闭信息的存储时,它就不会在那里被检索。但是dynamic_cast呢?

在最简单的情况下,dynamic_cast 是从某个基类型引用向下转换为派生类型引用 D&。派生类型不必是对象的最派生类型。因此,对于现在通用的动态调度 vtable 方案,对象的 vtable 指针不需要指向 D 类型的 vtable,因此不提供简单的成功检查。

对于仅限于单一继承的语言,纯粹向下转换的情况可以通过使用 vtable 本身作为类型标识符来解决,方法是通过 vtable 中的父指针搜索(单一)继承链。

图片中的多重继承使事情变得复杂。例如,如果类Derived 继承自Base1Base2,两者都是多态的,那么Derived 类的vtable 不能简单地扩展Base1 的vtable 和 em> 只需扩展 Base2 的 vtable。因此,如果Derived 虚表扩展了Base1,那么当将Derived* 重新解释为Base2* 时,指向对象的Derived 虚表指针将不再用作指向静态已知对象的指针类的虚表。

因此一个后果是,在存在多重继承的情况下,转换为基类型引用并不总是对指针类型进行简单的重新解释——可能必须调整指针值。

如何做到这一点非常不明显,以至于 Bjarne Stroustrup 不得不向自己证明,在向语言添加多重继承之前,可以实现多重继承的 vtable 方案。

我不知道当前的编译器如何处理它,特别是对于dynamic_cast,但由于简单的 vtable 父指针不适用于多重继承,逻辑上编译器无法通过该机制做到这一点:一些额外的支持数据需要结构、RTTI 信息。


"我想知道如何向下转换,然后检查它是否是指向正确类型的指针。不过,我无法修改所涉及的类或打开 RTTI。

如果您无法更改代码或打开 RTTI,您通常无法获取所需的信息。

在您控制所有对象实例化的特殊情况下,原则上您可以为每个对象维护一个单独的类型信息映射,但效率极低。

【讨论】:

  • 没有回答这个问题 - 为什么 dynamic_cast 需要 RTTI。
  • 我认为 RTTI 数据也常用于实现异常处理程序,因为类类型 catch 参数需要确定可能是任意类类型的异常对象是否具有给定的类型为明确的基础。
  • @aschepler:原则上可以通过dynamic_cast 完成,所以(假设它真的被使用了)它不是一个单独的用例。实际上,由于总是通过复制抛出异常,因此异常对象的最派生类型在throw 点是已知的。这允许与可能的处理程序进行非常有效的匹配。
【解决方案2】:

如果编译器在运行时插入了足够的数据以使dynamic_cast 工作,那么它们也将插入足够的数据以使 RTTI 工作。如果你可以dynamic_cast 引用另一个类型,你可以检查它是同一个类型还是另一个类型的后代。因此,这与默认打开 RTTI 相同。

举个例子,为什么编译器可能会为了提高效率而关闭它,如果你的派生类没有覆盖其父类的任何虚函数,会发生什么?编译器可能希望它简单地重用相同的虚函数表。它也不需要跟踪基础和派生关系来进行函数调度。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-26
    相关资源
    最近更新 更多