我知道虚方法允许派生类重写从基类继承的方法。何时使用虚拟方法是否合适/不合适?并不总是知道一个班级是否会被分类。一切都应该是虚拟的,只是“以防万一?”或者这会导致显着的开销吗?
答案 0 :(得分:9)
首先是一个有点迂腐的评论 - 在C ++标准中我们称它们为成员函数,而不是方法,尽管这两个术语是等价的。
我认为有两个原因不能使成员函数成为虚拟的。
final
关键字],这更好)。这也与意图有关。如果您不打算以多态方式使用该类,请不要将任何内容虚拟化。如果你任意虚拟成员,你就会招致Liskov Substitution Principle的滥用,这些错误类别很难追查和解决。答案 1 :(得分:7)
当你设计一个类时,你应该非常清楚它是否代表一个接口(在这种情况下你标记了适当的可重写方法和析构函数虚拟)或它是打算按原样使用,可能是组成或组合与其他对象。
换句话说,你的课程意图应该是你的指导。使一切虚拟化通常是过度的,有时会误导哪些方法旨在支持运行时多态性。
答案 2 :(得分:5)
这是一个棘手的问题。但是有一些指导方针/规则要遵循。
virtual
方法,只需要virtual
那些你需要自定义的方法儿童班。virtual
方法,则析构函数应为virtual
(讨论结束)。virtual
方法非公开,并提供负责评估前置条件和后置条件的公共包装器,以便派生类不会意外破坏它们。我认为这些很简单。我肯定让反射的ABI部分消失了,它只在传递DLL时才有用。
答案 3 :(得分:3)
如果您的代码遵循特定的设计模式,那么您的选择应该反映DP自己的原则。例如,如果您正在编写Decorator pattern,则应该是虚拟的函数是属于Component接口的函数。
否则,我想遵循一个渐进的方法,IOW我没有虚拟方法,直到我看到层次结构试图从你的代码中出现。
答案 4 :(得分:3)
例如,Java中的成员函数是100%虚拟的。在C ++中,它被视为代码大小/函数调用时间惩罚。另外,非虚函数保证函数实现始终相同(使用基类对象/引用)。 Scott Meyers在“Effective C ++”中详细讨论了它。
答案 5 :(得分:2)
我主要使用的健全性测试是 - 如果我定义的类是将来派生的,那么行为(函数)是否保持相同或是否需要重新定义。如果是,那么该函数是虚拟的有力竞争者,如果不是,那么,如果我不知道 - 我可能需要调查问题域以更好地理解我计划实现的行为。问题域主要给出了答案 - 如果不是,行为通常非关键。
答案 6 :(得分:1)
我想一种可能快速确定的方法是考虑你是否要处理一堆类似的类,你将用它来执行相同的任务,改变是方式你正在做那些任务。
一个简单的例子是计算各种几何图形区域的问题。你需要正方形,圆形,矩形,三角形等区域,这里唯一改变的是你用来计算面积的数学公式(方式)。因此,让这些形状中的每一个从公共基类继承并在基类中添加一个返回该区域的虚方法(然后可以在具有相应数学公式的每个子项中实现)是一个很好的决定。
将所有内容虚拟化为“以防万一”将使您的对象占用更多内存。此外,调用虚函数时会产生很小(但非零)的开销。因此,恕我直言,当性能/内存约束很重要时(这基本上意味着你所写的每个真实世界的程序),将一切虚拟“以防万一”都是不好的主意。
然而,根据要求的清晰程度以及预期的代码更改频率,这再次引起争议。例如,在一个快速而肮脏的工具或初始原型中,几个额外字节的内存和几毫秒的丢失时间并没有多大意义,为了这个缘故,可以拥有一堆(不必要的)虚函数灵活性。
答案 7 :(得分:0)
我的观点是,如果你想使用父类指针指向子类实例并使用它们的方法,那么你应该使用虚方法。
答案 8 :(得分:0)
虚方法是实现多态的一种方法。当你想要在更抽象的层次上定义一些动作时使用它们,这样就不可能实际实现它,因为它太笼统了。只有在派生类中,您才能知道如何执行该操作。但是,通过定义虚拟方法可以创建需求,这会增加类层次结构的刚性。这是否可取,取决于你想要获得的东西,以及你自己的品味。
答案 9 :(得分:-1)
看看Design Patterns。如果您的代码/设计是这些或类似之一,请使用虚拟功能。否则,请尝试this