10

在对 C++11 关键字的各种 解释final中,我看到了这样的例子。

class base
{
public:
    virtual void f() final;
};

class derived : public base
{
public:
    virtual void f();    // Illegal due to base::f() declared final.
};

这实际上是有用的用途final吗?为什么要在基类中声明一个虚函数(暗示它将在派生类中有用地重写)然后立即将其标记为final(否定该暗示)?有什么用处virtual void f() final

我可以看到标记derived::f()final 而不是base::f(). 在这种情况下,base::f()大概有一个很好的基于设计的理由说明为什么f()应该是虚拟的,并且derived::f()单独有一个很好的基于设计的理由说明为什么没有进一步的派生类应该覆盖其实现。

如果您不想多态地覆盖该函数,为什么不直接去掉 virtual 关键字呢?当然,派生类仍可能以非多态方式覆盖该函数。virtual void f() final因此,在基类中的目的是要base::f()以任何方式坚定地不可覆盖——无论是作为虚拟函数还是非虚拟函数?如果是这样,那么我们必须virtual在这种情况下添加关键字才能启用final. 我认为将非虚拟功能标记为最终功能应该是合法的。

当意义和意义似乎矛盾时,为什么要使用virtual void f() final源自基类的函数?virtualfinal

4

3 回答 3

25

将基类函数标记为虚拟函数和最终函数有什么意义吗?

是的,至少暂时如此。

我发现自己处于一个相对较大且不熟悉的现有 C++ 源代码库中。大部分代码是在 C++11 之前编写的。我发现我想确保基类中所有对虚函数的覆盖都用override. 困难的部分是找到所有这些覆盖。

我用 标记了基类中的虚函数,final编译器很快就向我展示了每个覆盖的声明位置。然后很容易按照我想要的方式装饰覆盖,并final从基类中的虚拟中删除。

于 2014-10-22T18:00:47.840 回答
4

您可以标记它virtual以表明它在您继承的类中是“虚拟的”(即使您不必这样做),并标记它final以表明从您的类派生的任何类都不能进一步覆盖它。例如,当您实现抽象基类时,可能会发生这种情况。这是 C++11,所以没用;override是一个更好的指示,因为它是由编译器强制执行的。

另一种可能性:您希望此方法不被覆盖,但您希望能够在不重新编译的情况下更改它。请记住,这virtual意味着它在虚拟表中。即使编译器不会让你覆盖它。

我认为您展示的示例的目的是展示virtual和最终之间的优先级,仅此而已。它是 的最小用途final,而不是有用的用途。

将非虚拟方法标记为final没有意义,因为无论如何您都无法覆盖它们。如果您希望编译器防止隐藏,那是一个完全不同的问题,与final. 从某种意义上说,非虚拟方法已经是最终的,但可以隐藏。

于 2013-05-24T16:06:05.597 回答
2

另一种方法是非虚函数。但是非虚函数可以被派生类隐藏。因此,如果您想防止函数隐藏,可以将其指定为 virtual final 。

于 2014-10-22T11:22:38.630 回答