http://en.wikipedia.org/wiki/Diamond_problem
意味はわかりますが、回避するにはどうすればよいですか?
http://en.wikipedia.org/wiki/Diamond_problem
意味はわかりますが、回避するにはどうすればよいですか?
実用的な例:
class A {};
class B : public A {};
class C : public A {};
class D : public B, public C {};
クラスDがBとCの両方から継承する方法に注意してください。ただし、BとCの両方がAから継承します。これにより、クラスAの2つのコピーがvtableに含まれることになります。
これを解決するには、仮想継承が必要です。仮想的に継承する必要があるのはクラスAです。したがって、これで問題が修正されます。
class A {};
class B : virtual public A {};
class C : virtual public A {};
class D : public B, public C {};
仮想継承。それが目的です。
インターフェイスの多重継承のみを使用することに固執します。クラスの多重継承は魅力的な場合もありますが、定期的に依存している場合は混乱や苦痛を伴うこともあります。
継承は強力で強力な武器です。本当に必要なときだけ使用してください。以前は、ダイヤモンドの継承は、ユーザーは「従業員」であると同時に「ウィジェット リスナー」でもあると言って、私が分類を遠ざける兆候でした。
このような場合、複数の継承の問題が発生しやすくなります。
コンポジションと所有者へのポインターを使用してそれらを解決しました。
前:
class Employee : public WidgetListener, public LectureAttendee
{
public:
Employee(int x, int y)
WidgetListener(x), LectureAttendee(y)
{}
};
後:
class Employee
{
public:
Employee(int x, int y)
: listener(this, x), attendee(this, y)
{}
WidgetListener listener;
LectureAttendee attendee;
};
はい、アクセス権は異なりますが、コードを複製せずにそのようなアプローチを回避できる場合は、それほど強力ではないため、より優れています。(他にないときのために電力を節約できます。)
class A {};
class B : public A {};
class C : public A {};
class D : public B, public C {};
これでは、クラス A の属性がクラス D で 2 回繰り返され、メモリ使用量が増えます...したがって、メモリを節約するために、Vtable に格納されるクラス A の継承されたすべての属性に対して仮想属性を作成します。
さて、Dreaded Diamond の素晴らしいところは、発生するとエラーになることです。回避する最善の方法は、事前に継承構造を把握することです。たとえば、私が取り組んでいる 1 つのプロジェクトには、ビューアーとエディターがいます。Editor は Viewer の論理的なサブクラスですが、すべての Viewer はサブクラス (TextViewer、ImageViewer など) であるため、Editor は Viewer から派生していないため、最終的な TextEditor、ImageEditor クラスはひし形を回避できます。
ひし形が避けられない場合は、仮想継承を使用します。ただし、仮想ベースの最大の注意点は、仮想ベースのコンストラクターが最も派生したクラスによって呼び出される必要があることです。つまり、実質的に派生するクラスはコンストラクターのパラメーターを制御できません。また、仮想ベースが存在すると、チェーンを介してキャストする際にパフォーマンス/スペースのペナルティが発生する傾向がありますが、最初のものを超えて多くのペナルティがあるとは思いません.
さらに、使用するベースを明示している場合は、いつでもダイヤモンドを使用できます。時にはそれが唯一の方法です。
より良いクラス設計を提案します。多重継承によって解決するのが最適な問題もあると思いますが、まず別の方法がないか確認してください。
そうでない場合は、仮想機能/インターフェースを使用してください。
委任による継承を使用します。次に、両方のクラスがベースAを指しますが、Aにリダイレクトするメソッドを実装する必要があります。これには、Aの保護されたメンバーがB、C、およびDの「プライベート」メンバーに変わるという副作用がありますが、現在はそうではありません。仮想が必要であり、あなたはダイヤモンドを持っていません。