【问题标题】:Requiring virtual function overrides to use override keyword要求虚函数覆盖使用 override 关键字
【发布时间】:2015-05-22 14:52:15
【问题描述】:

C++11 添加了override 以确保您编写的打算覆盖基类虚函数的成员函数实际执行(或不会编译)。

但是在大​​型对象层次结构中,有时您可能会意外地编写一个覆盖基类虚拟的成员函数,而您并不打算这样做!例如:

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
    }
};

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

【问题讨论】:

  • 实际上,您的函数将被命名为GazimpleWidget(Widget& w),显然C::GazimpleWidget(Widget& w) 仍然是小部件。当您尝试将C::GazimpleWidget( ) 缩写为C::GW( ) 时,您只会遇到此类问题。不要那样做。
  • @MSalters 我不明白这个评论。
  • @Barry:您的简化示例的问题在于foo 具有误导性。具有实名的实函数在无意中发生冲突的可能性要小得多。如果它们的名称相同,则它们应该执行相同的操作,然后覆盖可能不是错误。
  • @MSalters “不太可能……”、“应该……”、“可能不会……”。是的,很明显。问题的全部要点是发生了不太可能的情况,该功能未正确实现,我想在编译时验证这一点。

标签: c++ c++11 gcc overriding virtual


【解决方案1】:

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

-Wsuggest-override
警告重写未用 override 关键字标记的虚函数。

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

【讨论】:

    【解决方案2】:

    您可以做两件事。

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

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

    【讨论】:

      【解决方案3】:

      我看到-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 编译将失败......)

      【讨论】:

      • 我同意你的看法。但是,如果我们遵循建议,在首次引入新的虚函数时只在函数上使用“virtual”关键字,那么您会发现最终函数可能覆盖或可能不覆盖的问题离开。 (这不允许引入虚函数并将其实现为 final 的代码,无论如何这似乎是荒谬的。)然后含义很明确:“virtual”=新的非覆盖虚函数,而“override”或“final”都表示它们是覆盖(并且没有“虚拟”)并且两者都应该满足 g++ 警告(但不幸的是没有。)
      • 同时声明和完成一个基本的虚函数,从而破坏了它是虚拟的意义,似乎完全没有意义。我几乎会说语言应该不允许这样做,然后编译器就不必考虑它的哲学了。
      • 我同意@underscore_d 和 Scott Meyers 的观​​点。如果只有一种实现 f() 的方法,请坚定立场并声明它是非虚拟的。
      【解决方案4】:

      GCC 和 Clang 包含在其他答案中。 my other answer 的 VC++ 也是如此:

      下面是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 警告。

      【讨论】:

      • 问题是关于如何在重写方法上未使用“override”关键字时启用编译器警告,而不是关于如何启用错误使用 override 关键字的警告。
      猜你喜欢
      • 2023-03-05
      • 1970-01-01
      • 2021-07-30
      • 2013-10-04
      • 2015-04-20
      • 1970-01-01
      • 2021-09-30
      • 2015-06-17
      相关资源
      最近更新 更多