[c++] なぜ私はC ++で多重継承を避けるべきですか?


Answers

Bjarne Stroustrupとインタビューから:

複数の継承を使用して行うことができることは、単一の継承を使用して行うこともできるため、複数の継承を必要としないということは、きわめて正しく言います。 あなたは私が言及した委任のトリックを使用するだけです。 さらに、継承を一切必要としません。単一の継承で行うことは、クラスを介して継承することもできます。 実際には、ポインタとデータ構造ですべてを行うことができるので、クラスも必要ありません。 しかし、なぜあなたはそれをしたいですか? 語学施設を利用するのはいつ便利ですか? あなたはいつ回避策を好むでしょうか? 私は複数の継承が有用な場合を見てきましたが、複雑な多重継承が有用な場合も見てきました。 一般的に、私は、その言語で提供されている機能を使用して回避策をとることを好みます

Question

複数の継承を使用するのは良い考えですか?代わりに他のことをすることはできますか?




複数の継承を「避ける」べきではありませんが、「ダイヤモンド問題」( http://en.wikipedia.org/wiki/Diamond_problem )などの問題を認識し、あなたに与えられた力を注意深く扱うべきですあなたはすべての力を持っているべきです。




それは関係するクラス当たり4/8バイトを要する。 (クラスごとに1つのポインタ)。

これは決して心配しないかもしれませんが、ある日、あなたは数十億分の1秒のインスタンス化されたマイクロデータ構造を持っていれば、




すべてのプログラミング言語は、賛否両論のオブジェクト指向プログラミングのやり方が少し異なります。 C ++のバージョンは、パフォーマンスに重点を置いており、無効なコードを書き込むのは簡単ではないという付随する欠点があります。これは多重継承にも当てはまります。 結果として、この機能からプログラマーを離れる傾向があります。

他の人は、多重継承が何に良いものではないのかという問題に取り組んできました。 しかし、それを避ける理由が安全ではないということが多かれ少なかれ示唆されているという、かなりのコメントがあります。 はい、いいえ。

C ++でよくあることですが、基本的なガイドラインに従えば、常に「あなたの肩を見渡す」ことなく、安全に使うことができます。 重要なアイデアは、 "ミックスイン"と呼ばれる特別な種類のクラス定義を区別することです。 クラスはすべてのメンバ関数が仮想(または純粋仮想)である場合に混在します。 その後、あなたは1つのメインクラスと好きな数の "ミックスイン"から継承することができますが、ミックスインをキーワード "virtual"で継承する必要があります。 例えば

class CounterMixin {
    int count;
public:
    CounterMixin() : count( 0 ) {}
    virtual ~CounterMixin() {}
    virtual void increment() { count += 1; }
    virtual int getCount() { return count; }
};

class Foo : public Bar, virtual public CounterMixin { ..... };

私の提案は、クラスをミックスインクラスとして使うつもりなら、コードを読んでいる誰もが何が起こっているのかを見たり、基本的なガイドラインの規則で遊んでいることを確認したりするための命名規則を採用することです。 仮想基底クラスの仕組みのために、あなたのミックスインにもデフォルトのコンストラクタがあれば、もっとうまくいくことがわかります。 また、すべてのデストラクタを仮想化することも忘れないでください。

私がここで「ミックスイン」という言葉を使用しているのは、パラメータ化されたテンプレートクラスと同じではありません( このリンクを参照してください)。しかし、用語集を公正に使用していると思います。

今では、これが複数の継承を安全に使用する唯一の方法であるという印象を与えたくありません。 これは、チェックするのが簡単な単なる方法です。




w: 多重継承を参照してください。

複数の継承は批判を受けており、そのため、多くの言語で実装されていません。 批判には以下が含まれる:

  • 増加した複雑さ
  • 意味論的あいまいさはしばしばダイヤモンドの問題として要約される。
  • 1つのクラスから複数回明示的に継承できない
  • クラスのセマンティクスを変更する継承の順序。

C ++ / Javaスタイルのコンストラクタを使用する言語での多重継承は、コンストラクタやコンストラクタチェーンの継承問題を悪化させ、これらの言語でメンテナンスや拡張性の問題を引き起こします。 大きく異なった構築方法による継承関係のオブジェクトは、コンストラクタの連鎖パラダイムの下で実装するのが難しいです。

COMとJavaインターフェイスのようなインターフェイス(純粋な抽象クラス)を使用するためにこれを解決する現代的な方法。

私はこれの代わりに他のことをすることができますか?

はい、できます。 私はGoFから盗むつもりです。

  • インプリメンテーションではなくインターフェイスへのプログラム
  • 継承よりも構成を優先する






具体的なオブジェクトのMIに関する重要な問題は、合法的に「AでありBになる」べきオブジェクトを持つことはめったにないので、論理的根拠にはまれな解決策であることはめったにありません。 より多くの場合、 "CはAまたはBの役割を果たす"ことに従うオブジェクトCを持っています。これは、インタフェースの継承と合成によって実現できます。 しかし、間違いなく、複数のインターフェイスの継承は依然としてMIのサブセットです。

特にC ++の場合、機能の主な弱点は、多重継承の実際の存在ではありませんが、ほとんどの場合、不正な形式の構文があります。 たとえば、次のような同じオブジェクトの複数のコピーを継承します。

class B : public A, public A {};

定義によって誤っています。 これは英語で "BはAとAです"と翻訳されています。 したがって、人間の言語でさえ、重大なあいまいさがあります。 「Bは2 Asを持っている」、あるいは「BはAです」という意味ですか? そのような病理学的コードを許して、それを使用例にして悪化させたのは、後継言語でその機能を保持するケースを作ることになったときにC ++は好意的ではなかった。




Links