web-dev-qa-db-ja.com

ダイヤモンド問題

ダイヤモンド問題に関するウィキペディア:

「...菱形継承問題は、2つのクラスBとCがAから継承し、クラスDがBとCの両方から継承する場合に発生するあいまいさです。DのメソッドがAで定義されたメソッドを呼び出す場合(メソッドをオーバーライドしない場合) )、そしてBとCはそのメソッドを異なる方法でオーバーライドし、それからどのクラスから継承しますか:BまたはC?」

したがって、ダイヤモンドは次のようになります。

  A
 / \
B   C
 \ /
  D

私の質問は、そのようなクラスAがない場合はどうなるかということですが、BとCは同じメソッド、たとえばfoo()を宣言します。これは同じ問題ではありませんか?なぜそれはダイヤモンド問題と呼ばれるのですか?

例:

class B {
    public void foo() {...}
}

class C {
    public void foo() {...}
}

class D extends B, C {
}

new D().foo();
29
cretzel

それは同じ問題ではありません。

元の問題では、オーバーライドされたメソッドをAから呼び出すことができます。問題では、メソッドが存在しないため、これは当てはまりません。

菱形継承問題では、クラスAがメソッドFooを呼び出すと、衝突が発生します。通常、これは問題ありません。しかし、クラスDでは、Fooのどのインスタンスを呼び出す必要があるかを知ることはできません。

         +--------+
         |   A    |
         | Foo    |
         | Bar    |
         +--------+
            /  \
           /    \
          /      \
+--------+        +--------+
|   B    |        |   C    |
| Foo    |        | Foo    |
+--------+        +--------+
          \      /
           \    /
            \  /
         +--------+
         |   D    |
         |        |
         +--------+

あなたの問題では、メソッドを呼び出すことができる共通の祖先はありません。クラスDには、選択できるFooの2つのフレーバーがありますが、少なくとも2つあることはわかっています。そして、あなたは2つの中から選択することができます。

+--------+        +--------+
|   B    |        |   C    |
| Foo    |        | Foo    |
+--------+        +--------+
          \      /
           \    /
            \  /
         +--------+
         |   D    |
         |        |
         +--------+

しかし、いつものように、多重継承は必要ありません。集約とインターフェースを使用して、これらすべての問題を解決できます。

12
Toon Krijthe

菱形継承問題では、クラスDは暗黙的にクラスAから仮想メソッドを継承します。それを呼び出すために、クラスDは次を呼び出します。

A::foo()

クラスBとCの両方がこのメソッドをオーバーライドする場合、問題が発生し、実際に呼び出されます。

ただし、2番目の例では、クラスDが呼び出されたものを明示的に記述する必要があるため、これは当てはまりません。

B::foo()
C::foo()

したがって、問題は実際には同じではありません。菱形継承問題では、派生クラスではなく、それらの基本クラスを参照しているため、あいまいさがあります。

とにかく、それが私がそれを理解する方法です。

私はC++のバックグラウンドから来ていることに注意してください。

10
icabod