dynamic_cast<>

问题描述

所以我已经用 C++ 编程一段时间了,有人告诉我,使用动态转换将抽象类指针的指针转换为不同的具体类指针是不好的做法。

Shape* GeneralShape = new Triangle(...);
Triangle* triPtr = dynamic_cast<Triangle*>(GeneralShape);

其中 Shape 是一个抽象类,而 Triangle 继承自它。

当您继承的一个类与抽象类包含的一般函数相比,它的某个继承类稍有不同并且需要更多的函数时,使用动态类型转换似乎是一种访问成员函数的便捷方式。我只是想知道运行时多态有什么不好,或者有什么开销?

解决方法

虚拟分派的“运行时开销”相当低,除非在紧密循环中否则不太重要:

  • 查找正确的函数
  • 使用函数地址间接调用函数
  • 如果 CPU 分支预测器错误预测了调用,则管道会停止

dynamic_cast 增加了一些额外的开销:

  • 遍历类型继承的运行时表示以获得对象指针的正确调整因子(或失败)。如果继承图不深,这仍然很快。

更大的代价是在编译时错失优化机会。特别是在 C++ 中,使用编译时多态性(模板)经常会导致大量内联、消除循环、预计算等。当运行时多态性起作用时,这些优化通常是不可能的。

有趣的是,dynamic_cast 对编译时优化的障碍较小,因为编译器只需要考虑两种情况——cast 成功,cast 失败,程序员将这两种情况写成两个独立的代码路径,都受制于优化。相比之下,使用虚拟调用的“推荐”运行时多态方法要优化得多,因为可能的类型集是开放式的。

为了便于维护(如@user4581301 评论),虚拟调用通常比 dynamic_cast(或标记和切换)更受欢迎,而性能考虑是次要的。