关于多态性:何时将C++中的函数标记为虚拟?

When to mark a function in C++ as a virtual?

由于C++的静态绑定方法的性质,这会影响多态调用。

维基百科:

Although the overhead involved in this dispatch mechanism is low, it
may still be significant for some application areas that the language
was designed to target. For this reason, Bjarne Stroustrup, the
designer of C++, elected to make dynamic dispatch optional and
non-default. Only functions declared with the virtual keyword will be
dispatched based on the runtime type of the object; other functions
will be dispatched based on the object's static type.

所以代码:

1
2
Polygon* p = new Triangle;
p->area();

如果area()是父类中的non-virtual函数,而子类中的overridden函数,那么上面的代码将调用开发人员可能不希望调用的Parent's class method。(感谢我介绍的静态绑定)

因此,如果我想编写一个类供其他人使用(例如库),我是否应该使我的所有函数都是虚拟的,以使以前的代码按预期运行?


简单的答案是,如果您希望类的函数因运行时多态性而被重写,那么应该将它们标记为virtual,如果您不打算这样做,则不应标记为virtual

不要仅仅因为感觉到函数赋予了额外的灵活性就将函数标记为virtual,而应该考虑一下您的设计和公开接口的目的。例如:如果您的类不是为继承而设计的,那么使您的成员函数成为虚拟的将是误导性的。一个很好的例子是标准库容器,它们不打算被继承,因此它们没有虚拟析构函数。

没有理由不将所有成员函数标记为虚拟的、引用一些性能惩罚、非pod类类型等等,但是如果您真的打算将类用于运行时溢出,那么这就是它的目的以及它关于和超越所谓缺陷的目的。


如果派生类能够重写该方法,则将其标记为虚拟。就这么简单。


作为一般规则,如果类被显式设计为用作基类,并且该函数被设计为被重写,则只应将该函数标记为虚函数。实际上,大多数虚拟函数在基类中都是纯虚拟的。除调用反转的情况外,如果您显式地不提供覆盖函数的契约,那么虚拟函数应该是私有的(或最受保护的),并用执行契约的非虚拟函数进行包装。


在内存性能方面,如果任何东西是虚拟的,您都会得到一个虚拟指针表,因此查看它的一种方法是"请一个,请全部"。否则,如其他人所说,如果希望它们是可重写的,则将它们标记为虚拟的,这样在基类上调用该方法就意味着运行专门的版本。


这就是基本的想法;实际上,如果您使用的是父类,我认为您不需要重写每个方法,因此,如果您认为您将使用这种方法,只需使它们成为virtual