将基类函数标记为虚函数和final函数有什么意义吗?
Is there any sense in marking a base class function as both virtual and final?
在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
,这似乎有点不幸。我认为将非虚函数标记为final应该是合法的。
当virtual
的意义和final
的意义似乎相矛盾时,为什么要用virtual void f() final
来表示基类中的函数?
将基类函数标记为虚函数和final函数有什么意义吗?
是的,至少暂时是这样。
我发现自己在一个相对较大且不熟悉的现有c++源代码库中。大部分代码都是在c++ 11之前编写的。我发现我想确保基类中虚函数的所有重写都标记为override
。困难的部分是找到所有这些覆盖。
我用final
标记了基类中的虚函数,编译器很快向我展示了每个覆盖的声明位置。然后很容易按照我想要的方式装饰覆盖,并从基类中的虚拟中删除final
。
您可以将其标记为virtual
,以指示它在您继承的类中是'virtual'(即使您不必这样做),并将其标记为final
,以指示从您的类派生的任何类都不能进一步覆盖它。例如,在实现抽象基类时可能会发生这种情况。这是c++ 11,所以没有用;override
是一个更好的指示,因为它由编译器强制执行。
另一种可能性:您希望此方法不被重写,但您希望能够在不重新编译的情况下更改该方法。请记住,virtual
表示它在虚拟表中。即使编译器不允许你重写它
我认为您所展示的示例的目的是演示virtual
和final之间的优先级,仅此而已。这是final
的一个最小使用,而不是一个有用的
将非虚方法标记为final
是没有意义的,因为无论如何都不能覆盖它们。如果您希望编译器防止隐藏,那是一个完全不同的问题,这与final
方法无关。从某种意义上说,非虚方法已经是final了,但是是可隐藏的。
另一种选择是非虚函数。但是非虚函数可以被派生类隐藏。因此,如果想要防止函数隐藏,可以将其指定为virtual final。
- 什么时候调用组成单元对象的析构函数
- 当在同一名称空间中有两个具有相同签名的函数时,会发生什么
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- 什么时候调用析构函数
- 在两台机器之间进行时间戳的最佳c++chrono函数是什么
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 是什么原因导致它无法编译?它是声明签名还是在函数本身的实现中
- 我可以在这里替换什么,因为我不能在 C# 中使用隐式变量的 lambda 函数?
- 是什么让放置新调用对象的构造函数?
- 重载运算符的范围是什么?它是否会影响作为类成员的集合的插入函数?
- 如果我真的真的想从 STL 容器继承,并且我继承构造函数并删除新运算符,会发生什么?
- 函数名称表示什么等等
- 在函数中拥有函数原型的目的是什么?
- 使用基类指针调用基类的值构造函数的语法是什么?
- 什么是自定义比较器以及如何在 C++ 的排序函数中使用它?
- C++:使用方法调用析构函数的顺序是什么?
- 将此布尔值传递给此函数的最有效方法是什么?
- lambda函数什么时候对C++中的类有用
- 函数什么时候必须在c++中返回引用
- 如果void类型函数什么都不返回会发生什么