web-dev-qa-db-ja.com

すべての仮想関数を派生クラスに実装する必要がありますか?

これは単純な質問のように思えるかもしれませんが、他のどこにも答えが見つかりません。

私が次のものを持っていると仮定します:

class Abstract {
public:
    virtual void foo() = 0;
    virtual void bar();
}

class Derived : Abstract {
public:
    virtual void foo();
}

クラスDerivedがbar()関数を実装しなくても大丈夫ですか?私の派生クラスのすべてがbar()関数を必要としない場合、どうすればいいのでしょうか。抽象基本クラスのすべての仮想関数は、派生クラスに実装する必要がありますか、それとも純粋な仮想クラスにのみ実装する必要がありますか?ありがとう

81
mikestaub

派生クラスは、notall仮想関数自体を実装する必要があります。 pure onesのみを実装する必要があります。1 これは、質問のDerivedクラスが正しいことを意味します。それinherits祖先クラスbarからのAbstract実装。 (これは、Abstract::barはどこかに実装されています。質問のコードはメソッドを宣言していますが、定義していません。 Trenki's answer が示すようにインラインで定義することも、個別に定義することもできます。)


1 そして、それでも、派生クラスがinstantiatedになる場合のみ。派生クラスが直接インスタンス化されず、より多くの派生クラスの基本クラスとしてのみ存在する場合、すべての純粋な仮想メソッドを実装する責任があるのはthoseクラスです。階層の「中間」クラスは、基本クラスと同様に、一部の純粋な仮想メソッドを未実装のままにすることができます。 「中間」クラスdoesが純粋な仮想メソッドを実装する場合、その子孫はその実装を継承するため、自分で再実装する必要はありません。

72
Rob Kennedy

純粋な仮想メソッドのみを派生クラスに実装する必要がありますが、他の仮想メソッドの定義(単なる宣言ではなく)が必要です。提供しない場合、リンカは文句を言うかもしれません。

したがって、単に{}オプションの仮想メソッドの後、空のデフォルト実装が提供されます。

class Abstract {
public:
    virtual void foo() = 0; // pure virtual must be overridden
    virtual void bar() {}   // virtual with empty default implementation
};

class Derived : Abstract {
public:
    virtual void foo();
};

ただし、より複雑なデフォルトの実装では、別のソースファイルが使用されます。

42
trenki

ISO C++標準は、純粋仮想ではないクラスのすべての仮想メソッドを定義する必要があることを指定しています。

簡単に言うと、ルールは次のとおりです。
派生クラスが基本クラスの仮想メソッドをオーバーライドする場合、同様に定義を提供する必要があります。そうでない場合、基本クラスはそのメソッドの定義を提供する必要があります。

コード例の上記のルールに従って、virtual void bar();にはBaseクラスの定義が必要です。

参照:

C++ 03標準:10.3仮想関数[class.virtual]

クラスで宣言された仮想関数は、そのクラスで定義されるか、そのクラスで純粋(10.4)、またはその両方で宣言されます。しかし、診断は不要です(3.2)。

そのため、関数を純粋な仮想にするか、定義を提供する必要があります。

gcc faqも文書化します:

ISO C++標準では、純粋仮想ではないクラスのすべての仮想メソッドを定義する必要がありますが、このルールの違反[class.virtual]/8に対する診断は必要ありません。この仮定に基づいて、GCCは暗黙的に定義されたコンストラクター、代入演算子、デストラクタ、およびそのような最初の非インラインメソッドを定義する変換ユニット内のクラスの仮想テーブルのみを発行します。

したがって、この特定のメソッドの定義に失敗すると、リンカーは明らかに無関係なシンボルの定義の欠如について不平を言う場合があります。残念ながら、このエラーメッセージを改善するには、リンカを変更する必要がある場合があり、これは常に実行できるとは限りません。

解決策は、純粋ではないすべての仮想メソッドが定義されるようにすることです。デストラクターは、純粋仮想[class.dtor]/7と宣言されている場合でも定義する必要があることに注意してください。

7
Alok Save

はい、それは結構です...抽象基本クラスから派生したクラスをインスタンス化するために、純粋な仮想関数を実装するだけです。

3
Jason

はい、派生クラスが親クラスのPure Virtualである機能をオーバーライドする必要があることは正しいです。純粋仮想関数を持つ親クラスは、子クラスが独自の純粋仮想関数の本体を提供する必要があるため、抽象クラスと呼ばれます。

通常の仮想機能の場合:-子クラスにその機能がある場合とない場合があるため、それらをさらにオーバーライドする必要はありません。

仮想関数メカニズムの主な目的は、実行時多態性です。純粋仮想関数(抽象クラ​​ス)の主な目的が、自分の体と同じ名前の関数を持つことを必須にすることです。

0
CodeCodeCode