“final”的方法:省略“virtual”

Recipe for `final`: omit `virtual`?

本文关键字:省略 virtual final 方法      更新时间:2023-10-16

如果我写final(对成员函数),就不应该写virtual,这是一个有效的配方吗?

在基类中,final方法没有意义:

struct Driver {
    virtual void print();
};

如果将final添加到print(),这将首先违背多态性的原因。因此,这将是无用的(尽管可能)。

当我从这个类派生时,我可以用 final检测错误,但只有没有 virtual:

struct KeyboardDriver : public Driver {
    virtual void prynt() final;    // Oops: typo, but compiler-ok
};
struct MouseDriver : public Driver {
    void prynt() final;    // Error: Hooray, compiler found my typo
};

KeyboardDriver::prynt的附加final是合法的。因为final只要求成员函数为virtual——编译器让它通过(FDIS 9.2p9)。

但是当我省略virtual时,错别字使该函数成为非虚函数——它没有覆盖任何内容,即没有虚函数。因此,没有virtualfinal在这方面的作用与override相同。

更新:我的分析正确吗?没有virtualfinal的功能是否包括override的功能?

你的分析是正确的。不将final成员标记为virtual可以避免声明一个新的、未重写的成员并捕获错误。然而,由于这是override的目的,使用final override可能更简单;那么成员是否被标记为virtual就无关紧要了。

这不是final的作用。你要找的是override

struct Base { 
  virtual void print();
};
struct Derived : Base {
  void prynt() override; //compiler error
};
struct Good : Base {
  void print() override; //no compiler error
};

如果你将一个函数标记为override,而它不是,那么你会得到一个错误。结合您的最终函数,您将获得编译器检查安全性的所有舒适,并且在编码标准要求时显式标记函数virtual的清晰度。

struct Best : Base {
  virtual void print() final override;
};

我不认为这是一个错误,它只是一个虚函数,不能重载。如果函数在父类中声明为虚函数,也会发生同样的事情,因为虚声明是继承的。禁止它是没有意义的。

我的分析正确吗?没有virtual的final的功能是否包括override的功能?

。这是一个编译器错误的原因:

void prynt() final;    // Error: Hooray, compiler found my typo

是因为final只允许在函数上使用。编译器报错,因为你在一个非虚函数上使用了它。

这一行没有语法错误:

virtual void prynt() final;    // Oops: typo, but compiler-ok

这可能不是你想要的,但这是合法的(甚至是有意义的,取决于具体情况)代码。

你遇到的问题是由于想要这样做:

struct Driver {
    virtual void print();
};
struct MouseDriver : public Driver {
    void print();
};

省略virtual在技术上是合法的。但就我个人而言,我一直觉得这是一种糟糕的形式。将重要信息(这些函数将被覆盖)放入另一个类中。我认为这是一个错误,甚至允许编译。

如果您想避免这个问题,那么在所有虚函数上显式地声明virtual,并在您打算创建新函数的地方使用override。那么,这将无法正确编译。
struct Driver {
    virtual void print();
};
struct MouseDriver : public Driver {
    virtual void print() override;
};