[英]Avoiding dynamic_cast/RTTI
我最近正在为一个附带项目( cpp-markdown
库,出于好奇)编写一段 C++ 代码,并遇到了一个我想提出一些意见的编码问题。
cpp-markdown
有一个名为Token
的基础 class ,它有许多子类。 两个主要的子类是Container
(其中包含其他Token
的 collections )和TextHolder
(当然,用作包含文本的Token
的基础 class )。
大多数处理是通过虚函数处理的,但其中一些处理最好在单个 function 中处理。 为此,我最终使用dynamic_cast
将指针从Token*
向下转换为其子类之一,因此我可以调用特定于子类及其子类的函数。 强制转换不可能失败,因为代码能够通过虚函数(例如isUnmatchedOpenMarker
)判断何时需要这样的东西。
我可以看到其他两种方法来处理这个问题:
创建我想调用的所有函数作为Token
的虚函数,并为每个子类留下一个空的主体,除了需要处理它们的子类,或者......
在Token
中创建一个虚拟 function ,当在某些子类型上调用this
时,它将返回正确类型的指针,如果在其他任何东西上调用它,则会返回一个 null 指针。 基本上是我已经在那里使用的虚拟 function 系统的扩展。
对我来说,第二种方法似乎比现有的方法和第一种方法都好。 但我想知道其他有经验的 C++ 开发人员对此的看法。 或者我是否过于担心琐事。 :-)
#1 污染了 class 命名空间和不需要它的对象的 vtable。 好的,当您有一些通常可以实现的方法时,但是当只需要单个派生的 class 时,就显得很丑陋了。
#2 只是穿着圆点连衣裙和口红的dynamic_cast<>
。 不会使客户端代码更简单,并且会混淆整个层次结构,要求基础和每个派生的 class 半感知所有其他派生的 class。
只需使用dynamic_cast<>
。 这就是它的用途。
如果您知道转换不会无效,那么只需使用 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.