12

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

来自维基百科:

尽管这种分派机制涉及的开销很低,但对于该语言旨在针对的某些应用程序领域来说,它可能仍然很重要。出于这个原因,C++ 的设计者 Bjarne Stroustrup 选择将动态调度设为可选且非默认。只有使用 virtual 关键字声明的函数才会根据对象的运行时类型进行调度;其他函数将根据对象的静态类型进行调度。

所以代码:

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

如果这area()是Child 类中的non-virtualParent 类中的函数,overridden则上面的代码将调用Parent's class method开发人员可能不期望的函数。(感谢我介绍的静态绑定)

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

4

5 回答 5

26

简单的答案是,如果您打算为运行时多态性覆盖类的函数,则应将它们标记为virtual,如果您不打算这样做,则不要这样做。

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

没有理由不将所有成员函数标记为虚拟,引用一些性能损失,非 POD 类类型等,但如果您真的打算将您的类用于运行时覆盖,那么这就是目的它及其关于和超过所谓的缺陷。

于 2011-11-28T15:35:29.570 回答
3

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

于 2011-11-28T15:33:36.470 回答
2

作为一般规则,只有该类被明确设计为用作基类并且该函数被设计为被覆盖时,才应将函数标记为虚拟。实际上,大多数虚函数在基类中都是纯虚函数。并且除了在调用反转的情况下,您明确地不为覆盖函数提供合同,虚拟函数应该是私有的(或最多受保护的),并用执行合同的非虚拟函数包装。

于 2011-11-28T17:18:31.390 回答
1

在内存性能方面,如果有任何东西是虚拟的,你会得到一个虚拟指针表,所以一种看待它的方式是“请一个,请所有”。否则,正如其他人所说,如果您希望它们可被覆盖,则将它们标记为虚拟,以便在基类上调用该方法意味着运行专用版本。

于 2011-11-28T15:40:36.180 回答
0

基本上就是这样;实际上,如果您使用的是父类,我认为您不需要重写每个方法,所以virtual如果您认为您会以这种方式使用它,只需创建它们即可。

于 2011-11-28T15:27:29.373 回答