web-dev-qa-db-ja.com

オーバーライドキーワードを使用するために仮想関数のオーバーライドを要求する

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を使用することを強制したいだけです。

40
Barry

GCC 5.1リリースでは warning が追加されたようです。

-Wsuggest-override
オーバーライドキーワードでマークされていない仮想関数のオーバーライドについて警告します。

-Wsuggest-override-Werror=suggest-overrideでコンパイルすると、すべてのオーバーライドでoverrideが使用されるようになります。

33
Barry

できることは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ベースメンバー関数をオーバーライドしようとする派生クラスをすべて検索します。その後、不足しているものを修正できます。これはもう少し手間がかかり、クラス階層が拡大したときに頻繁に再確認する必要があります。

13
TemplateRex

-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コンパイルは失敗します...)

6
user46317