重複の可能性:
多重継承の正確な問題は何ですか?
複数のインターフェースを実装することは悪ではないのに、なぜ多重継承は悪と見なされるのですか? 特に、インターフェースが単に純粋な抽象クラスであると考えたときは?
(多かれ少なかれ) 多重継承の正確な問題は何ですか? 、C# での複数の継承、その他...
重複の可能性:
多重継承の正確な問題は何ですか?
複数のインターフェースを実装することは悪ではないのに、なぜ多重継承は悪と見なされるのですか? 特に、インターフェースが単に純粋な抽象クラスであると考えたときは?
(多かれ少なかれ) 多重継承の正確な問題は何ですか? 、C# での複数の継承、その他...
多重継承の一般的な問題は「ダイヤモンド問題」です。
A
/ \
B c
\ /
D
A の仮想メソッドが B と C の両方で実装されている場合、D を作成するとどちらが得られますか?
これがインターフェイスの問題ではない理由は、インターフェイスには実装がないためです。したがって、A/B/C がすべてインターフェイスである場合、D は適切な方法で A メソッドを実装する方法を選択します。
特に基本クラスが純粋に抽象的ではない (データ メンバーがない) 場合、人々が通常予想するよりも複雑で、より多くの問題を引き起こすため、それは悪であると認識されています。ダイヤモンドの継承は、共通のベースが共有される仮想継承を使用して解決できます。また、コンパイラはメソッド シグネチャの競合をキャッチできます。うまく使えば、エレガントで DRY なソリューションを生成できますが、それ以外の場合は、インターフェイスやコンポジション/委任を介して実装するのがより冗長になります。
C++ の一般的な MI イディオムの 1 つは、基本コンストラクターを重要なメンバー オブジェクトで構築する必要がある複雑なラッパー コンストラクター用です。基本オブジェクトはメンバー オブジェクトの前に構築する必要があるため、MI (「メンバーからのベース」) を使用するのがコツです。そうしないと、ファクトリを使用して、Java のように構築を行うための追加の手順を実行する必要があります (Java には、非インターフェイス クラスの MI がありません)。
それを恐れず、適切な場合に使用してください (ただし、適切なものを見つけるにはある程度の練習が必要になる場合があります)。
MI は、まれな問題に対する非常に複雑なソリューションほど悪いものではありません。ほとんどの場合、同じことを行うためのより良い方法があります。
A が z というメソッドを実装し、b が z というメソッドを実装している場合、どのように調整しますか?
子:a、b
ここで、クライアント コードが new child().z() を呼び出すとします。どの実装が呼び出されていますか? 私はそれが悪いことだとは思わない