繁体   English   中英

避免 dynamic_cast/RTTI

[英]Avoiding dynamic_cast/RTTI

我最近正在为一个附带项目( cpp-markdown,出于好奇)编写一段 C++ 代码,并遇到了一个我想提出一些意见的编码问题。

cpp-markdown有一个名为Token的基础 class ,它有许多子类。 两个主要的子类是Container (其中包含其他Token的 collections )和TextHolder (当然,用作包含文本的Token的基础 class )。

大多数处理是通过虚函数处理的,但其中一些处理最好在单个 function 中处理。 为此,我最终使用dynamic_cast将指针从Token*向下转换为其子类之一,因此我可以调用特定于子类及其子类的函数。 强制转换不可能失败,因为代码能够通过虚函数(例如isUnmatchedOpenMarker )判断何时需要这样的东西。

我可以看到其他两种方法来处理这个问题:

  1. 创建我想调用的所有函数作为Token的虚函数,并为每个子类留下一个空的主体,除了需要处理它们的子类,或者......

  2. Token中创建一个虚拟 function ,当在某些子类型上调用this时,它将返回正确类型的指针,如果在其他任何东西上调用它,则会返回一个 null 指针。 基本上是我已经在那里使用的虚拟 function 系统的扩展。

对我来说,第二种方法似乎比现有的方法和第一种方法都好。 但我想知道其他有经验的 C++ 开发人员对此的看法。 或者我是否过于担心琐事。 :-)

#1 污染了 class 命名空间和不需要它的对象的 vtable。 好的,当您有一些通常可以实现的方法时,但是当只需要单个派生的 class 时,就显得很丑陋了。

#2 只是穿着圆点连衣裙和口红的dynamic_cast<> 不会使客户端代码更简单,并且会混淆整个层次结构,要求基础和每个派生的 class 半感知所有其他派生的 class。

只需使用dynamic_cast<> 这就是它的用途。

如果你想变得聪明,你还可以构建一个双分派模式,这是访问者模式的三分之二。

  • 创建一个包含空虚拟visit(SpecificToken*)方法的基础TokenVisitor class。
  • 向 Token 添加一个虚拟accept(TokenVisitor*)方法,该方法在传递的 TokenVisitor 上调用正确类型的方法。
  • 从 TokenVisitor 派生出您需要以不同方式对所有令牌执行的各种操作。

对于对树结构有用的完整访问者模式,让默认的accept方法迭代调用token->accept(this); 在各个。

如果您知道转换不会无效,那么只需使用 static_cast。

为什么要避免使用dynamic_cast 它是否会导致您的应用程序出现不可接受的瓶颈? 如果不是,那么现在可能不值得对代码做任何事情。

如果您可以在特定情况下以一定的安全性换取一点速度,那么您应该可以进行static_cast 但是,这巩固了您的假设,即您知道 object 的类型,并且演员阵容没有变坏的可能性。 如果以后您的假设变得错误,您的代码中可能会出现一些神秘的崩溃错误。 回到我最初的问题,你真的确定这里的权衡值得吗?

至于您列出的选项:第一个听起来不像是一个解决方案,而是我希望在凌晨 3 点编写代码时看到的最后一分钟的黑客攻击。 功能向 class 层次结构的基础逐渐渗透是 OOP 新手遇到的最常见的反模式之一。 不要这样做。

对于第二个选项,您列出的任何类似的选项实际上只是重新实现dynamic_cast - 如果您在一个只有废话编译器可用的平台上(我听说过有关 Gamecube 的编译器占用了系统可用 RAM 的四分之一以及 RTTI 信息的故事)这可能是值得的,但很可能您只是在浪费时间。 你真的确定这是值得你关心的事情吗?

防止 dynamic_cast 的真正干净方法是将正确类型的指针放在正确的位置。 抽象应该注意 rest。

恕我直言,dynamic_cast 有此声誉的原因是,每次您在 class 层次结构中向下添加另一个子类型时,它的性能都会下降一点。 如果层次结构中有 4-5 个类,则无需担心。

好玩的东西。 分词器中的dynamic_cast意味着您实际上希望将 Token 拆分为基于文本 stream 中的当前 position 和 Token 中的逻辑创建 Token 的东西。 每个令牌要么是独立的,要么必须像上面一样创建一个令牌才能正确处理文本。

这样你就可以提取通用的东西,仍然可以根据令牌的层次结构进行解析。 您甚至可以在不使用dynamic_cast的情况下使整个解析器由数据驱动。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM