要求虚函数重写以使用 override 关键字

Requiring virtual function overrides to use override keyword

C++11 添加了 override 以确保您编写的成员函数打算覆盖 base-class 虚函数实际上可以(或不会编译)。

但是在大型对象层次结构中,有时您可能会意外地编写一个成员函数来覆盖 base-class virtual,而这并不是您想要的!例如:

struct A {
    virtual void foo() { }  // because obviously every class has foo().
};

struct B : A { ... };

class C : B {
private:
    void foo() {
        // was intended to be a private function local to C
        // not intended to override A::foo(), but now does
    }
};

是否有一些编译器 flag/extension 至少会在 C::foo 上发出警告?为了可读性和正确性,我只想强制所有覆盖使用 override.

您可以做两件事。

首先,Clang 3.5 及更高版本有一个 -Winconsistent-missing-override 警告(由 -Wall 触发)。这对您的示例不太适用,但前提是您将 void foo() override {} 添加到 class B 而不是 class C。您真正想要的是 -Wmissing-override,找到所有丢失的 override,而不仅仅是不一致丢失的那些。目前没有提供,但您可能会在 Clang 邮件列表上抱怨,他们可能会添加它。

其次,您使用Howard Hinnant's trick临时final添加到基class成员函数并重新编译。然后,编译器将定位所有进一步派生的 class 试图覆盖 virtual 基本成员函数的对象。然后你可以修复丢失的。这需要更多工作,并且需要在 class 层次结构扩展时经常重新检查。

看起来 GCC 5.1 版本添加了我正在寻找的warning

-Wsuggest-override
       Warn about overriding virtual functions that are not marked with the override keyword.

使用 -Wsuggest-override -Werror=suggest-override 编译将强制所有覆盖使用 override.

GCC 和 Clang 包含在其他答案中。 VC++ 来自 my other answer:

下面是VC++中的相关警告编号:

C4263 (level 4) 'function': member function does not override any base class virtual member function
C4266 (level 4) 'function': no override available for virtual member function from base 'type'; function is hidden

要启用这两个警告,您可以使用以下选项之一:

  1. 在项目设置中将警告级别设置为 4,然后禁用不需要的警告。这是我的首选方式。要禁用不需要的 4 级警告,请转到项目设置 > C/C++ > 高级,然后在禁用特定警告框中输入警告编号。
  2. 使用代码启用以上两个警告。

    #pragma warning(default:4263)
    #pragma warning(default:4266)
    
  3. 在项目设置 > C/C++ > 命令行中启用以上两个警告,然后输入 /w34263 /w34266。这里的 /wNxxxx 选项表示在级别 N 中启用 xxxx 警告(N = 3 是默认级别)。您还可以执行 /wdNxxxx 以禁用级别 N 中的 xxxx 警告。

我看到 -Werror=suggest-override 的问题是它不允许您编写以下内容:

void f() final {...}

尽管这里有一个隐含的override-Werror=suggest-override 不会忽略这一点(它应该如此,因为在这种情况下 override 是多余的)

但比这更复杂...如果你写

virtual void f() final {...}

它的意思和

完全不同
virtual void f() override final {...}

第一种情况不需要覆盖任何东西!第二个。

所以我假设 GCC 检查是以这种方式实现的(即有时接受冗余 override),以便使最后一个案例正确。但这并不能很好地发挥作用,例如使用 clang-tidy,这将在 final 足够时正确删除覆盖(但 GCC 编译将失败...)