web-dev-qa-db-ja.com

「オーバーライド」キーワードは、オーバーライドされた仮想メソッドの単なるチェックですか?

私の知る限り、C++ 11でのoverrideキーワードの導入は、実装されている関数がoverride関数のvirtual関数であることを確認するためのチェックに過ぎません基本クラス。

それですか?

203
aiao

それがまさにアイデアです。重要なのは、あなたが何を意味するのかを明確にして、そうでなければ静かなエラーを診断できるようにすることです:

struct Base
{
    virtual int foo() const;
};

struct Derived : Base
{
    virtual int foo()   // whoops!
    {
       // ...
    }
};

上記のコードはコンパイルされますが、意図したものではありません(欠落しているconstに注意してください)。代わりにvirtual int foo() overrideと言った場合、関数が実際には何もオーバーライドしていないというコンパイラエラーが発生します。

232
Kerrek SB

ウィキペディアの引用:

特別な識別子のオーバーライドは、コンパイラが基本クラスをチェックして、この正確なシグネチャを持つ仮想関数があるかどうかを確認することを意味します。存在しない場合、コンパイラはエラーを出力します。

http://en.wikipedia.org/wiki/C%2B%2B11#Explicit_overrides_and_final

編集(答えを少し改善しようとしています):

メソッドを「オーバーライド」と宣言するということは、そのメソッドが基本クラスの(仮想)メソッドを書き換えることを意図していることを意味します。オーバーライドするメソッドは、書き換えるメソッドと同じ署名(少なくとも入力パラメーターに対して)を持っている必要があります。

なぜこれが必要なのですか?さて、次の2つの一般的なエラーは防止されます。

  1. 新しいメソッドで型を誤って入力します。コンパイラは、以前のメソッドを記述するつもりであることを知らず、単に新しいメソッドとしてクラスに追加します。問題は、古いメソッドがまだ存在し、新しいメソッドがオーバーロードとして追加されることです。この場合、古いメソッドへのすべての呼び出しは以前と同じように機能し、動作を変更することはありません(これは書き換えのまさに目的でした)。

  2. スーパークラスでメソッドを「仮想」として宣言するのを忘れますが、それでもサブクラスでメソッドを書き直そうとします。これは明らかに受け入れられますが、動作は意図したとおりにはなりません。メソッドは仮想ではないため、スーパークラスへのポインターを介したアクセスは、新しい(サブクラス)メソッドではなく、古い(スーパークラス)メソッドの呼び出しを終了します。

「オーバーライド」を追加すると、これが明確に明確になります。これにより、コンパイラーに次の3つのことを期待していることがわかります。

  1. スーパークラスに同じ名前のメソッドがあります
  2. スーパークラスのこのメソッドは「仮想」として宣言されています(つまり、書き換えが意図されています)
  3. スーパークラスのメソッドには、サブクラスのメソッド(書き換えメソッド)と同じ(入力*)シグネチャがあります

これらのいずれかが偽の場合、エラーが通知されます。

*注:出力パラメーターは異なる場合がありますが、関連するタイプです。必要に応じて、共変および反変の変換についてお読みください。

31
user1284631

override」は、誰かがオプションのパラメーターを追加するなど、基本クラスの仮想メソッドのシグネチャを更新したが、派生クラスのメソッドのシグネチャを更新するのを忘れたときに役立ちます。その場合、基底クラスと派生クラスの間のメソッドは多態的な関係ではなくなります。オーバーライド宣言がないと、この種のバグを見つけるのは困難です。

26
user3792211

はい、そうです。これは、オーバーライドを試行せず、不正な署名を介して混乱させないようにするためのチェックです。これを詳細に説明するWikiページがあり、簡単な説明例を示します。

http://en.wikipedia.org/wiki/C%2B%2B11#Explicit_overrides_and_final

5
RonaldBarzell

C++ 17標準ドラフト

C++ 17 N4659標準ドラフト のすべてのoverrideヒットを調べた後、override識別子への唯一の参照は次のとおりです。

5仮想関数がvirt-specifierオーバーライドでマークされていて、基本クラスのメンバー関数をオーバーライドしない場合、プログラムの形式は正しくありません。 [例:

struct B {
  virtual void f(int);
};

struct D : B {
  virtual void f(long) override; // error: wrong signature overriding B::f
  virtual void f(int) override;  // OK
}

—終了例]

だから、間違ったプログラムを爆破することが実際には唯一の効果だと思う。