Java 基本上是完全端到端设计的,以加速该精确场景:
- 对象总是通过引用访问(这样你就可以在同一个类层次结构中混合和匹配不同的类型。你可以创建一个 Fruit 对象数组,它也可以自然地存储 Banana 对象。这不会影响性能,但是它使使用运行时多态性的代码更容易编写。
- 它使用垃圾收集器,允许对象在分配后在内存中移动,因此,即使数组只存储引用,引用的对象也可以打包在连续内存中,以最大限度地减少缓存未命中,否则会严重损害性能
- 该语言是 JIT 的(或在某些情况下是解释的),因此在运行时,JVM 可以查看虚拟调用,并在许多情况下将其优化为常规函数调用。
C++ 没有所有这些机制:在 C++ 中必须通过引用/指针来存储和访问对象既乏味又容易出错,而且效率低下(数组成员指向的对象不会被分配到彼此,因此访问每个对象可能会导致缓存未命中)。而当 C++ 编译器遇到虚拟调用时,它通常无法确定将调用哪个函数,因此它无法优化掉虚拟性。当它不能这样做时,它也不能内联调用(C++ 编译器严重依赖于性能)。
但另一方面,C++ 也不需要如此依赖它。相反,C++ 为您提供了强大的静态多态性,通常可以替代使用,完全消除了开销。
所以是的,运行时多态性、虚拟调用和继承在 C++ 中通常更昂贵,因为它没有加速它所需的大量管道。但同时,C++ 也使运行时多态性更难使用,并且在许多情况下,它提供了可供您使用的替代方案。
人们经常声称“虚拟调用的代价只是指针间接”,但它有许多微妙的代价,正如上面所暗示的:它禁止函数内联,并且需要使用引用语义来处理对象,这又会影响内存影响 CPU 缓存利用率的局部性。它具有广泛的影响,Java 是从头开始有效地设计的,以尽可能多地弥补这些影响。C++ 不是,而且在大多数情况下,当使用运行时多态性时,它必须承受性能损失。
当然,典型的 C++ 程序员也可能比Java 程序员更关心性能(例如,你不会经常听到 Java 程序员讨论他们的代码的 CPU 缓存利用率)
如果我必须在 c++ 中开发一个运行时,该运行时在其上托管同样用 c++ 开发的应用程序,我将采用以下方法 <...>
请不要。如上所述,C++ 代码通常不会也不应该使用运行时多态性来解决所有问题。在 Java 中,它实际上是您可以访问的唯一工具,它被使用,并且必须使用,并且应该非常广泛地使用。在 C++ 中,它是整个选项工具箱中的一个工具。当有替代品时,通常最好避免使用。
涉及成本,但这也使我们将应用程序与运行时分离。如果没有虚拟方法,应用程序将始终与运行时具有链接时间依赖性。
和?有这样的链接时间依赖性有问题吗?您要在应用程序运行时更换它吗?