在 C++ 中,您什么时候更喜欢虚函数而不是模板?

When you prefer virtual functions over templates in C++?

我面试了一家金融公司,被问到这个问题:
"List the case(s) when you prefer virtual functions over templates?"

这对我来说听起来很奇怪,因为通常我们的目标是相反的,对吗?
所有的书籍、文章、演讲都在鼓励我们使用静态多态性而不是动态多态性。

是否有任何我不知道的已知情况,何时应该使用虚函数并避免使用模板?

当编译时不知道对象的类型时,使用virtual方法。

例如

void Accept (Fruit* pFruit)  // supplied from external factors at runtime
{
  pFruit->eat();   // `Fruit` can be anyone among `Apple/Blackberry/Chickoo/`...
}

根据用户输入的内容,将向函数提供水果。因此,我们无法弄清楚 eat() 会是什么。所以它是运行时多态性的候选者:

class Fruit
{
  public: virtual void eat () = 0;
}

在所有其他情况下,始终首选静态多态性(包括 templates)。它更具确定性和易于维护。

GUI/可视化小部件工具包是一个明显的例子。例如,重新实现一个 draw 方法,使用虚拟方法和动态调度肯定不会那么麻烦。由于现代 C++ 倾向于不鼓励原始指针管理,std::unique_ptr 可以为您管理资源。

我敢肯定还有很多其他层次结构的例子你可以想出...一个游戏的基础 enemy class,用虚拟方法处理各种坏人的行为: )

关于动态调度的整个 'overhead' 论点在今天完全没有根据。我认为,几十年来,vtable 间接实现并没有成为严重工作负载的重大开销。还有一个更有趣的问题,如果 C++ 是今天设计的,多态性会成为语言的一部分吗? 但现在既不存在也不存在。


我不希望这个问题一直悬而未决,因为它不是一个直接的编程问题,而且可能太容易受到意见的影响。 software engineering.

可能是个更好的问题

面试问题似乎是在询问偏好(以及您的推理)。 我更喜欢接口(虚拟方法)以便于为单元测试创​​建模拟。我们可以为这些使用模板,但它很麻烦(消费者必须模板化)。如果分析显示 vtable 查找没有速度下降,请优先使用 mocking/testing 非虚拟方法。

此外,键入擦除。我认为它根本不能使用模板来实现。类型擦除大致可以认为是void ptr和函数指针,使用接口+虚方法可以轻松实现。

模板需要代码实现才能可用。我相信一个接口的虚拟方法可以在一个子 ptr 上调用它的二进制(对象)文件。

不确定使用模板的代码膨胀是否是现代编译器的问题,但如果可执行文件的大小显着增加,这可能是内存有限的嵌入式系统的问题,这些系统不喜欢使用模板。