web-dev-qa-db-ja.com

C ++仮想関数を安全にオーバーライドする

仮想関数を持つ基本クラスがあり、派生クラスでその関数をオーバーライドしたい。派生クラスで宣言した関数が実際に基本クラスの関数をオーバーライドするかどうかをコンパイラにチェックさせる方法はありますか?古い関数をオーバーライドする代わりに、誤って新しい関数を宣言しないようにするマクロまたは何かを追加したいと思います。

次の例をご覧ください。

_class parent {
public:
  virtual void handle_event(int something) const {
    // boring default code
  }
};

class child : public parent {
public:
  virtual void handle_event(int something) {
    // new exciting code
  }
};

int main() {
  parent *p = new child();
  p->handle_event(1);
}
_

ここでは、parent::handle_event()の代わりにchild::handle_event()が呼び出されます。これは、子のメソッドがconst宣言を欠いているため、新しいメソッドを宣言するためです。これは、関数名のタイプミスか、パラメータタイプのわずかな違いでもあります。また、基本クラスのインターフェースが変更され、どこか派生クラスが変更を反映するように更新されなかった場合にも簡単に発生します。

この問題を回避する方法はありますか?コンパイラまたは他のツールにこれを確認するように何らかの方法で指示できますか?有用なコンパイラフラグ(g ++が望ましい)これらの問題をどのように回避しますか?

98
sth

G ++ 4.7以降では、新しいC++ 11 overrideキーワードを理解します。

class child : public parent {
    public:
      // force handle_event to override a existing function in parent
      // error out if the function with the correct signature does not exist
      void handle_event(int something) override;
};
85
Gunther Piez

C#のoverrideキーワードのようなものはC++の一部ではありません。

Gccでは、-Woverloaded-virtualは、同じ名前の関数で基本クラスの仮想関数を非表示にすることを警告しますが、署名は十分に異なるため、オーバーライドされません。ただし、関数名自体のつづりが間違っているために関数のオーバーライドに失敗するのを防ぐことはできません。

20
CB Bailey

私の知る限り、単に抽象化することはできませんか?

class parent {
public:
  virtual void handle_event(int something) const = 0 {
    // boring default code
  }
};

Www.parashift.comで、抽象メソッドを実際に実装できると読んだと思いました。個人的には理にかなっていますが、唯一のことは、サブクラスに強制的に実装させることだけです。

17
Ray Hidayat

MSVCでは、CLR用にコンパイルしていない場合でも、CLR overrideキーワードを使用できます。

G ++では、すべての場合にそれを強制する直接的な方法はありません。他の人は、_-Woverloaded-virtual_を使用して署名の違いをキャッチする方法について良い答えを与えています。将来のバージョンでは、誰かが__attribute__ ((override))またはC++ 0x構文を使用した同等の構文を追加する可能性があります。

11
Doug

MSVC++では、 キーワードoverride を使用できます

class child : public parent {
public:
  virtual void handle_event(int something) <b>override</b> {
    // new exciting code
  }
};

overrideは、MSVC++のネイティブコードとCLRコードの両方で機能します。

9
bobobobo

関数を抽象化し、派生クラスがそれをオーバーライドする以外の選択肢を持たないようにします。

@Rayあなたのコードは無効です。

class parent {
public:
  virtual void handle_event(int something) const = 0 {
    // boring default code
  }
};

抽象関数では、ボディをインラインで定義することはできません。に変更する必要があります

class parent {
public:
  virtual void handle_event(int something) const = 0;
};

void parent::handle_event( int something ) { /* do w/e you want here. */ }
5
Tanveer Badar

私はあなたの論理にわずかな変更を提案します。何を達成する必要があるかに応じて、機能する場合と機能しない場合があります。

handle_event()はまだ「退屈なデフォルトコード」を実行できますが、仮想ではなく、「新しいエキサイティングなコード」を実行したい時点で、基底クラスに抽象メソッド(つまり、オーバーライドする必要がある)メソッドを実行させますこれは、子孫クラスによって提供されます。

編集:そして、あなたの子孫クラスのいくつかがnotが「新しいエキサイティングなコード」を提供する必要があると後で決定した場合、抽象を仮想に変更し、その「挿入」の空の基本クラス実装を提供できます機能。

3
JMD

コンパイラには、基本クラス関数が非表示になった場合に生成できるという警告が表示される場合があります。存在する場合は、有効にします。これにより、constの衝突とパラメーターリストの違いが検出されます。残念ながら、これはスペルミスを発見することはありません。

たとえば、これはMicrosoft Visual C++の警告C4263です。

2
Mark Ransom