65

http://en.wikipedia.org/wiki/Diamond_problem

意味はわかりますが、回避するにはどうすればよいですか?

4

8 に答える 8

75

実用的な例:

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 {};
于 2008-09-26T12:57:52.653 に答える
14

仮想継承。それが目的です。

于 2008-09-26T01:39:24.183 に答える
13

インターフェイスの多重継承のみを使用することに固執します。クラスの多重継承は魅力的な場合もありますが、定期的に依存している場合は混乱や苦痛を伴うこともあります。

于 2008-09-26T01:49:50.880 に答える
6

継承は強力で強力な武器です。本当に必要なときだけ使用してください。以前は、ダイヤモンドの継承は、ユーザーは「従業員」であると同時に「ウィジェット リスナー」でもあると言って、私が分類を遠ざける兆候でした。

このような場合、複数の継承の問題が発生しやすくなります。

コンポジションと所有者へのポインターを使用してそれらを解決しました。

前:

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;
};

はい、アクセス権は異なりますが、コードを複製せずにそのようなアプローチを回避できる場合は、それほど強力ではないため、より優れています。(他にないときのために電力を節約できます。)

于 2008-09-27T06:09:02.643 に答える
3
class A {}; 
class B : public A {}; 
class C : public A {}; 
class D : public B, public C {};

これでは、クラス A の属性がクラス D で 2 回繰り返され、メモリ使用量が増えます...したがって、メモリを節約するために、Vtable に格納されるクラス A の継承されたすべての属性に対して仮想属性を作成します。

于 2012-07-15T19:07:43.273 に答える
2

さて、Dreaded Diamond の素晴らしいところは、発生するとエラーになることです。回避する最善の方法は、事前に継承構造を把握することです。たとえば、私が取り組んでいる 1 つのプロジェクトには、ビューアーとエディターがいます。Editor は Viewer の論理的なサブクラスですが、すべての Viewer はサブクラス (TextViewer、ImageViewer など) であるため、Editor は Viewer から派生していないため、最終的な TextEditor、ImageEditor クラスはひし形を回避できます。

ひし形が避けられない場合は、仮想継承を使用します。ただし、仮想ベースの最大の注意点は、仮想ベースのコンストラクターが最も派生したクラスによって呼び出される必要があることです。つまり、実質的に派生するクラスはコンストラクターのパラメーターを制御できません。また、仮想ベースが存在すると、チェーンを介してキャストする際にパフォーマンス/スペースのペナルティが発生する傾向がありますが、最初のものを超えて多くのペナルティがあるとは思いません.

さらに、使用するベースを明示している場合は、いつでもダイヤモンドを使用できます。時にはそれが唯一の方法です。

于 2008-09-26T02:01:42.787 に答える
1

より良いクラス設計を提案します。多重継承によって解決するのが最適な問題もあると思いますが、まず別の方法がないか確認してください。

そうでない場合は、仮想機能/インターフェースを使用してください。

于 2008-09-26T12:50:37.973 に答える
0

委任による継承を使用します。次に、両方のクラスがベースAを指しますが、Aにリダイレクトするメソッドを実装する必要があります。これには、Aの保護されたメンバーがB、C、およびDの「プライベート」メンバーに変わるという副作用がありますが、現在はそうではありません。仮想が必要であり、あなたはダイヤモンドを持っていません。

于 2011-02-11T23:24:59.943 に答える