【问题标题】:How is dynamic_cast typically implemented?dynamic_cast 通常是如何实现的?
【发布时间】:2011-03-19 21:37:02
【问题描述】:

类型检查仅仅是整数比较吗?或者有一个GetTypeId 虚函数来区分哪个会使其成为整数比较是否有意义?

(只是不希望对类名进行字符串比较)

编辑:我的意思是,如果我经常期待错误的类型,那么使用以下内容是否有意义:

struct Token
{
    enum {
        AND,
        OR,
        IF
    };
    virtual std::size_t GetTokenId() = 0;
};

struct AndToken : public Token
{
    std::size_t GetTokenId() { return AND; }
};

并使用GetTokenId 成员而不是依赖dynamic_cast

【问题讨论】:

  • @YeenFei:我知道 Dynamic_Cast 实际上做了什么,我只是好奇(出于各种原因)我是否应该依赖它而不是为令牌提供我自己的类型代码。
  • 如果 RTTI 是您的应用程序的开销,请考虑使用类型特征。我在stackoverflow.com/questions/2377636/… 上发布了一些示例
  • 奇怪的是没有人提到,virtual 基类是另一种蠕虫,这里不讨论...
  • 可能是因为我们从像瘟疫这样的虚拟基地运行 :)

标签: c++ dynamic-cast


【解决方案1】:

dynamic_cast 的功能远远超出了简单的类型检查。如果它只是一个类型检查,它会很容易实现(就像你在原始帖子中的那样)。

除了类型检查之外,dynamic_cast 还可以执行对void * 的强制转换和分层交叉强制转换。从概念上讲,这些类型的转换需要一些在两个方向(向上和向下)遍历类层次结构的能力。支持这种类型转换所需的数据结构比单纯的标量类型 id 更复杂。 dynamic_cast 使用的信息是 RTTI 的一部分。

试图在这里描述它会适得其反。我曾经有一个很好的链接,描述了 RTTI 的一种可能实现......将尝试找到它。

【讨论】:

  • 那么,在我的情况下,标量类型 id 就足够了,我应该使用这样的标量吗?
  • @Billy ONeal:嗯,是的……如果你真的需要的话。除了我不明白你为什么决定使用size_t 作为返回类型。 size_t 与这一切无关。
  • 我使用size_t 作为默认的无符号整数类型。
  • 强制转换为void* 可以说是最简单的情况:它是一个简单的运行时偏移量,例如隐式转换为虚拟基类。
  • @AnT 您是否有机会从您的答案中找到承诺的链接? ;-)
【解决方案2】:

我不知道具体的实现方式,但这里有一个想法:

Derived*Base* 的转换可以在编译时完成。两种不相关的多态类型之间的转换也可以在编译时完成(只返回 NULL)。

Base*Derived* 的转换需要在运行时完成,因为可能有多个派生类。动态类型的识别可以使用绑定到对象的虚方法表来完成(这就是它需要多态类的原因)。

此 VMT 可能包含有关基类及其数据偏移量的额外信息。这些数据偏移在涉及多重继承时是相关的,并被添加到源指针以使其指向正确的位置。

如果在基类中找不到所需的类型,dynamic_cast 将返回 null。

【讨论】:

    【解决方案3】:

    在一些原始编译器中你是对的,他们使用了字符串比较。

    因此 dynamic_cast 非常慢(相对而言),因为在层次结构链上/下的每一步都需要遍历类层次结构,因此需要一个字符串与类名称进行比较。

    这导致很多人开发自己的铸造技术。这几乎总是徒劳的,因为它要求每个类都被正确注释,当出现问题时几乎不可能追踪错误。

    但这也是古老的历史。

    我不确定它现在是如何完成的,但它绝对不涉及字符串比较。自己做也是一个坏主意(永远不要做编译器已经在做的工作)。您所做的任何尝试都不会像编译器那样快或准确,请记住,多年的发展已经使编译器代码尽可能快(而且它总是正确的)。

    【讨论】:

    • 我怀疑现在是通过比较 vtbl 指针来完成的,这些指针很可能与超类(父)指针相关联。如果您知道要转换的对象的类和所需的类(模板参数),那么从这些类中的每一个获取 vtbl 指针并沿继承树前进,直到您找到(或不)一个共同点就足够简单了基类。
    • @Drew Hall。是的,这也是一种技术(或与您的描述非常相似的东西)。但是自从我查看 gcc 的来源以来已经有几年了,所以我实际上并不知道。但是我好像记得看过一篇关于更高效机制的论文,但是我已经很久没有活跃在编译器领域了。
    • “我不确定现在是如何完成的,但它肯定不涉及字符串比较”。我不太确定,今天我看到我的分析器中显示了“strcmp”。在“strcmp”程序集中设置断点后,我看到它被“dynamic_cast”调用...我目前对使用 Microsoft Visual Studio 2005 感到难过,希望自那以后情况有所改善!
    • 我不确定是否可以避免字符串比较(或类似的东西),使用多个 DLL 和来自一个 DLL 中创建的对象的dynamic_cast。一个成功的dynamic_cast 可能不需要任何字符串比较就可以完成,但是如果有一个成功的dynamic_cast 需要字符串比较来验证,那么每个失败的dynamic_cast 都需要做一个字符串比较来表明它不是覆盖...
    • 字符串,还是字符串等价物?我希望看到一些证据:甚至是他们如何做到这一点的想法。如果您有一个纯头文件类A 用于两个不同的 DLL,一个派生类 B1 在一个 DLL 中,B2 在另一个 DLL 中,dynamic_cast 应该如何在没有完全限定的 DLL 之间工作在类型中编码并比较的A 的名称?我想运行时中的全局类型注册表将字符串比较推送到 DLL 加载可能会起作用,或者散列以使字符串比较更快,但必须比较字符串等价物。
    【解决方案4】:

    编译器无法预测您可能拥有的其他信息并将其粘贴在 dynamic_cast 中。如果你知道你的代码的某些不变量并且你可以证明你的手动转换机制更快,那就自己做吧。在这种情况下如何实现 dynamic_cast 并不重要。

    【讨论】:

    • 不幸的是,我还没有编写大量代码,但是从一个转换到另一个将是一项不平凡的操作。有大量代码显示“这个标记是 AND 吗?” ... “这个标记是 OR 吗?” ... 除了确定我是否有正确的类型之外,实际上并不需要实际的演员表本身。
    猜你喜欢
    • 2013-08-23
    • 2017-03-09
    • 1970-01-01
    • 2011-05-13
    • 2016-03-04
    • 2012-10-25
    • 1970-01-01
    • 2011-06-20
    • 2012-11-26
    相关资源
    最近更新 更多