要求虚函数重写以使用 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
要启用这两个警告,您可以使用以下选项之一:
- 在项目设置中将警告级别设置为 4,然后禁用不需要的警告。这是我的首选方式。要禁用不需要的 4 级警告,请转到项目设置 > C/C++ > 高级,然后在禁用特定警告框中输入警告编号。
使用代码启用以上两个警告。
#pragma warning(default:4263)
#pragma warning(default:4266)
在项目设置 > 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 编译将失败...)
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
要启用这两个警告,您可以使用以下选项之一:
- 在项目设置中将警告级别设置为 4,然后禁用不需要的警告。这是我的首选方式。要禁用不需要的 4 级警告,请转到项目设置 > C/C++ > 高级,然后在禁用特定警告框中输入警告编号。
使用代码启用以上两个警告。
#pragma warning(default:4263) #pragma warning(default:4266)
在项目设置 > 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 编译将失败...)