为什么向下转换在 C++ 中是一种不好的做法,而不是在另一种语言中?

Why would down casting be a bad practice in C++ and not in another language?

我曾经问过一个关于如何设计一段 C++ 代码的问题(可以在此处找到 C++ - Good or bad practice?),人们告诉我向下转换被认为是一种不好的做法,除了非常特定的场景。

但是,我已经看到很多 C# 和 Java 代码片段,其中它似乎是一种完全自然的做事方式。例如,在 Android SDK 中,您具有 Activity#findViewById() 函数 returns 一个视图,然后将其向下转换为实际的 class:

TextView tv = (TextView) this.findViewById( R.id.myTextView );

为什么需要在 C++ 中避免这种情况而不是在其他语言中?
我知道 C# 和 Java 都原生支持内省,而不是 C++,后者需要某种类型的字段,但最终它是一回事,不是吗?

在其他解释器语言中,类型检查是在 JVM 等解释器中完成的。在 C++ 中,您必须手动进行类型检查。

至少有几个非常不同的原因,所有这些都很重要:

  1. 概念:其他语言(尤其是Java,但在很大程度上也包括强烈鼓励使用"reference types") 使用 运行 时多态性作为单一工具来解决许多不同的问题(编译时多态性、代码重用、性能增强、类型擦除、运行 时多态性等。 ),而 C++ 对个别问题有不同的、更专业的和更合适的解决方案。 (模板、值类型等可用于解决个别问题。)因此,C++ 中的多态性在其他语言中不太常见,而在其余常见的情况下,它通常(但不总是)不适合使用向下转换或 instanceof.

  2. Pragmatic:与其他运算符的性能相比,C++ 中的向下转换运算符基本上非常慢,在主要部分是因为 C++ 允许多重继承和虚拟继承。其他语言没有,因此它们的转换要简单得多。此外,某些编译器的实现 本身 在历史上向下转换的实现甚至更慢(例如,我相信 64 位 Visual C++ 就是其中之一)。因此,除了概念原因 (#1) 之外,由于其实际性能特征,开发人员会不惜一切代价避免使用它。

由于这些原因,除非绝对需要,否则在 C++ 中使用 dynamic_cast 确实是个坏主意。

在 C++ 中使用相同的习惯用法,其中 API 接受一个处理程序并将 void*long 传递给它,或者存储这样一个带有 [=19 实例的变量=] 的对象。在WINAPI中,RegisterClass是前者的典型,Set/GetWindowLongPtr是后者的典型。这些是你提到的 "very specific scenarios",它适用于托管语言和 C++。

通常,静态类型语言会避免向下转型,因为它将类型检查从编译转移到 运行 时间。