将基类函数标记为虚拟和最终是否有任何意义?

时间:2013-05-24 16:01:31

标签: c++ c++11 virtual final

在C ++ 11的final关键字的various explanations中,我看到的是这样的示例。

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 void f() final在基类中的目的是使base::f()以任何方式牢固地不可覆盖 - 作为虚函数还是非虚函数?如果是这样,那么在这种情况下我们必须添加virtual关键字才能启用final似乎有点不幸。我认为将非虚拟函数标记为最终函数应该是合法的。

为什么当virtual void f() final的感觉与virtual的感觉似乎相矛盾时,使用final来源于基类中的函数?

3 个答案:

答案 0 :(得分:19)

  

将基类函数标记为虚拟和最终是否有任何意义?

是的,至少是暂时的。

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

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

答案 1 :(得分:4)

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

另一种可能性:您希望不重写此方法,但您希望能够在不重新编译的情况下更改此方法。请记住,virtual表示它位于虚拟表中。即使编译器不允许你覆盖它。

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

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

答案 2 :(得分:1)

替代方案是非虚拟功能。但是非虚函数可以被派生类隐藏。因此,如果您想要阻止函数隐藏,可以将其指定为虚拟最终函数。