由于方法静态绑定的C++特性,这会影响多态调用。
来自维基百科:
尽管这种调度机制所涉及的开销很低对于某些应用领域来说,该语言可能仍然很重要是为目标而设计的。因此,Bjarne StroustrupC++的设计者,选择使动态调度成为可选的非默认。只有使用virtual关键字声明的函数才会基于对象的运行时类型进行调度;其他功能将基于对象的静态类型进行调度。
所以代码:
Polygon* p = new Triangle;
p->area();
如果area()
是Parent类中的non-virtual
函数,而Child类中的是overridden
,则上面的代码将调用开发人员可能不期望的Parent's class method
。(感谢我介绍的静态绑定(
那么,如果我想写一个供其他人使用的类(例如库(,我是否应该让我的所有函数都是虚拟的,以便之前的代码按预期运行
简单的答案是,如果您打算为运行时多态性覆盖类的函数,则应该将它们标记为virtual
,如果您不打算这样做,则不应该这样做。
不要仅仅因为觉得函数赋予了额外的灵活性就将其标记为virtual
,而是要考虑您的设计和公开接口的目的。例如:如果你的类不是为了继承而设计的,那么让你的成员函数成为虚拟函数会产生误导。这方面的一个很好的例子是标准库容器,它不是要继承的,因此它们没有虚拟析构函数。
没有理由不将所有成员函数标记为虚拟的,引用一些性能惩罚、非POD类类型等等,但如果你真的认为你的类是运行时过度加载的,那么这就是它的目的,也是所谓的缺陷。
如果派生类应该能够覆盖该方法,则将其标记为虚拟。就这么简单。
就内存性能而言,如果有任何东西是虚拟的,那么您会得到一个虚拟指针表,因此查看它的一种方法是"please one,please all"。否则,正如其他人所说,如果你希望它们是可重写的,那么就把它们标记为虚拟的,这样在基类上调用该方法就意味着运行了专门的版本。
作为一般规则,只有当类被明确设计为用作基类,并且该函数被设计为被重写时,才应将函数标记为virtual。在实践中,大多数虚拟函数在基类中将是纯虚拟的。除了在调用反转的情况下,明确不为覆盖函数提供约定,虚拟函数应该是私有的(或者最多是受保护的(,并用强制约定的非虚拟函数封装。
基本上就是这个想法;实际上,如果您使用的是父类,我认为您不需要覆盖所有方法,所以如果您认为将以这种方式使用,只需将它们设为virtual
即可。