我了解到,虚方法允许派生类覆盖从基类继承的方法。何时使用虚方法是恰当/不恰当的?并不总是知道一个类是否会被子类化。是否应该将所有内容都设为虚拟的,只是“以防万一”?还是那样会引起重大开销?
首先,稍微有点学究气的是在 C++ 的标准中,我们称之为成员函数(member functions),而不是方法(methods),尽管这两个术语是等效的。
我认为有两个原因不应该将成员函数声明为虚函数。
final
关键字,这更好)。同时,这也涉及到意图。如果你没有打算通过多态使用该类,则不要将任何内容声明为虚函数。如果随意将成员函数声明为虚函数,就会引发违反 里氏替换原则 的问题,而这类错误很难跟踪和解决。我猜,快速确定的一种可能方式是考虑你是否要处理一堆类似的类,这些类用于执行相同的任务,唯一变化的是你处理这些任务的方式。
一个微不足道的例子是计算各种几何图形的面积问题。你需要正方形、圆形、长方形、三角形等的面积,这里唯一变化的是你使用的数学公式(方式)来计算面积。因此,将每个形状从一个共同的基类中继承出来,并添加一个在基类中返回面积的虚拟方法(然后在每个子类中使用各自的数学公式实现),这将是一个好决策。
对于每个对象都让其成为虚函数“以防万一”,将会使你的对象占用更多的内存。此外,在调用虚函数时还会有一些小的(但非零)开销。因此,在性能/内存约束很重要的情况下(这基本上意味着你编写的每个真实世界程序),让所有东西都成为虚函数“以防万一”是一个不好的想法,也就是说一般并不适用。
然而,这又是有争议的,取决于需求清晰程度以及代码更改的频率。例如,在一个快速粗糙的工具或初始原型中,如果多用一些(不必要的)虚函数来增加灵活性,导致多占用几个字节的内存和几毫秒的时间损失并不会带来太大影响,那么这样做就可以接受。
虚方法是实现多态性的一种方式。当您想要在更抽象的级别上定义某些操作,以至于实际上无法实现它们,因为它们太普遍时,就会使用它们。只有在派生类中,您才能告诉如何执行该操作。但是,通过定义虚方法,您创建了一个要求,这增加了类层次结构的严格性。这可能是明智的或不明智的,这取决于您想要获得什么以及您自己的品味。