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
を使用することを強制したいだけです。
GCC 5.1リリースでは warning が追加されたようです。
-Wsuggest-override
オーバーライドキーワードでマークされていない仮想関数のオーバーライドについて警告します。
-Wsuggest-override
-Werror=suggest-override
でコンパイルすると、すべてのオーバーライドでoverride
が使用されるようになります。
できることは2つあります。
まず、Clang 3.5以降には_-Winconsistent-missing-override
_警告があります(_-Wall
_によってトリガーされます)。これは、あなたの例ではまったく機能しませんが、void foo() override {}
を_class B
_ではなく_class C
_に追加する場合のみです。実際に必要なのは、一貫性のない欠落したものだけでなく、欠落しているすべてのoverride
を見つけるための_-Wmissing-override
_です。現在は提供されていませんが、Clangのメーリングリストで苦情を申し立てて追加する場合があります。
次に、 Howard Hinnant's trick totemporarilyadd final
を基本クラスのメンバー関数に追加し、再コンパイルします。その後、コンパイラは、virtual
ベースメンバー関数をオーバーライドしようとする派生クラスをすべて検索します。その後、不足しているものを修正できます。これはもう少し手間がかかり、クラス階層が拡大したときに頻繁に再確認する必要があります。
-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コンパイルは失敗します...)