在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
来源于基类中的函数?
答案 0 :(得分:19)
将基类函数标记为虚拟和最终是否有任何意义?
是的,至少是暂时的。
我发现自己处于一个相对较大且不熟悉的现有C ++源代码库中。大部分代码都是在C ++ 11之前编写的。我发现我想确保基类中虚函数的所有覆盖都标有override
。困难的部分是找到所有这些覆盖。
我使用final
在基类中标记了虚函数,编译器很快向我展示了每个覆盖声明的位置。然后很容易装饰我想要的覆盖,并从基类中的虚拟中删除final
。
答案 1 :(得分:4)
您可以将其标记为virtual
以表明您正在继承的类中是“虚拟”(即使您不必执行此操作),并将其标记为final
以指示没有从您的类派生的类可能会进一步覆盖它。例如,当您实现抽象基类时,可能会发生这种情况。这是C ++ 11,所以没用; override
是一个更好的指示,因为它是由编译器强制执行的。
另一种可能性:您希望不重写此方法,但您希望能够在不重新编译的情况下更改此方法。请记住,virtual
表示它位于虚拟表中。即使编译器不允许你覆盖它。
我认为您展示的示例的目的是展示virtual
和最终之间的优先级,仅此而已。它是final
的 minimal 用法,而不是有用的。
将非虚拟方法标记为final
毫无意义,因为无论如何都无法覆盖它们。如果您希望编译器阻止隐藏,那是一个完全不同的问题,这与final
方法无关。从某种意义上说,非虚拟方法已经是最终的,但是可以隐藏。
答案 2 :(得分:1)
替代方案是非虚拟功能。但是非虚函数可以被派生类隐藏。因此,如果您想要阻止函数隐藏,可以将其指定为虚拟最终函数。