【问题标题】:Using Virtual Function with Final keyword使用带有 Final 关键字的虚函数
【发布时间】:2019-08-21 12:54:12
【问题描述】:

我有一个关于在 C++ 中使用关键字 final 的问题。我了解虚函数是在基类中声明的成员函数,预计会在派生类中被覆盖。通过动态绑定,将调用适当的方法,具体取决于负责调用的对象的类型。但是,为了防止基类中的成员函数在任何派生类中被覆盖,我们将使用 final 关键字。

void startEngine() final;// Compile error!
virtual void startEngine() final; //No error

为什么我们使用“final”来防止基类中的成员函数在派生类中被覆盖,同时我们仍然必须一起使用关键字VIRTUAL(允许覆盖)。

我尝试删除 virtual 这个词,但出现编译错误:“nonvirtual function cannot be declared with 'final' modifier”

【问题讨论】:

  • 如果不是虚拟的,则不能被覆盖。
  • 我明白了,但是当我们使用 VIRTUAL 时(这意味着我们希望它被覆盖),那么为什么我们仍然必须一起声明 FINAL (这意味着我们不希望它被覆盖) .
  • 这意味着我们已经遇到了一个虚函数链的末端。除此之外,实现更多的虚函数就没有意义了。

标签: c++ virtual-functions


【解决方案1】:

首先,只有当函数可以被重写时,我们才能停止重写函数。所以final 只对虚函数有意义。

不过,final 应用于单个类的虚函数可能看起来毫无意义。但是,如果您考虑更复杂的层次结构,事情就会发生变化:

class Parent
{
public:
    virtual ~Parent() = default;
    virtual void f();
};
class Child : public Parent
{
public:
    void f() final; // f IS virtual already...
};
class GrandChild : public Child
{
    // cannot override f any more – while Child still could!
};

此外,请考虑以下事项:

class Base
{
public:
    virtual ~Base() = default;
    void f(); // non-virtual! (i. e. cannot be overridden)
};
class Derived : public Base
{
public:
    void f(); // does not override, but HIDEs Base::f!!!
};

同时声明 Base::f virtual 和 final 也可以防止隐藏(但不会过度加载)。

实际上,如果Base 本身已经从另一个多态类继承,那么这种情况还是很有意义的。如果不是并且Base 不打算被继承,我根本不会引入任何虚函数(虚函数调用比普通函数调用更昂贵!)。如果那时用户仍然继承并隐藏了一个函数——好吧,他自己的责任......

【讨论】:

  • 在你的第二个例子中,为什么我们不在基类中的 void f() 后面加上“final”以防止它被覆盖?
  • @James 因为它不是虚拟的,并且无论如何不能被覆盖。 final (按标准)旨在停止/防止覆盖,但如果你无论如何都不能这样做...将final应用于非虚拟函数以防止隐藏可能 是一种选择。但它没有进入标准,就是这样......隐藏功能(通常)一个相当糟糕的主意,但显然标准委员会选择让用户负责......
猜你喜欢
  • 1970-01-01
  • 2011-10-26
  • 1970-01-01
  • 2018-06-17
  • 2012-11-10
  • 1970-01-01
  • 2015-05-22
  • 1970-01-01
  • 2019-05-31
相关资源
最近更新 更多