問題タブ [diamond-problem]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
c++ - ダイヤモンドの継承 (C++)
ダイヤモンドの継承を持つことは悪い習慣と見なされていることを私は知っています. ただし、ダイヤモンドの継承が非常にうまく適合すると感じるケースが 2 つあります。これらの場合にダイヤモンドの継承を使用することをお勧めしますか、それともより良い別のデザインがありますか.
ケース 1:システムでさまざまな種類の「アクション」を表すクラスを作成したいと考えています。アクションは、いくつかのパラメーターによって分類されます。
- アクションは「読み取り」または「書き込み」です。
- アクションは、遅延ありでも遅延なしでもかまいません (1 つのパラメーターだけではありません。動作が大幅に変わります)。
- アクションの「フロー タイプ」は、FlowA または FlowB です。
以下のデザインを予定しています。
もちろん、2 つのアクション (Action クラスから継承) が同じメソッドを実装することはありません。
ケース 2:システムに「コマンド」の複合設計パターンを実装します。コマンドは、読み取り、書き込み、削除などを行うことができます。また、読み取り、書き込み、削除などを行うことができるコマンドのシーケンスも必要です。コマンドのシーケンスには、他のコマンドのシーケンスを含めることができます。
だから私は次のデザインを持っています:
さらに、特別な種類のコマンド、「モダン」コマンドがあります。1 つのコマンドと複合コマンドの両方を最新にすることができます。「モダン」であることにより、特定のプロパティ リストが 1 つのコマンドと複合コマンドに追加されます (両方のプロパティはほとんど同じです)。CommandAbstraction へのポインターを保持し、必要なコマンドの種類に応じて (new を介して) 初期化できるようにしたいと考えています。だから私は(上記に加えて)次のデザインをしたい:
繰り返しますが、CommandAbstraction クラスから継承する 2 つのクラスが同じメソッドを実装しないようにします。
ありがとうございました。
c++ - 多重継承 + 仮想関数の混乱
次のようなダイヤモンドの多重継承シナリオがあります。
共通の親である A は、仮想関数 fn() を定義します。
B と C の両方が を定義することは可能fn()
ですか?
そうである場合、次の質問は、D が B と C の両方の fn() に明確化せずにアクセスできるかどうかです。これにはいくつかの構文があると思います..
そして、BとCが誰であるかを具体的に知らなくても、Dがそれを行うことは可能ですか? B と C は他のいくつかのクラスに置き換えることができ、D のコードをジェネリックにしたいと考えています。
私がやろうとしているのは、D にその祖先にある fn() のすべてのインスタンスを何らかの方法で列挙させることです。これは、仮想関数という他の手段で可能ですか?
java - Java での多重継承
Java は複数のクラスからの継承を許可していません (それでも、複数のインターフェースからの継承は許可されています)。私はそれが古典的なひし形の問題と非常に一致していることを知っています。しかし、私の質問は、複数の基本クラスから継承する際にあいまいさがない (したがってダイヤモンドの問題の可能性がない) 場合に、Java が C++ のような多重継承を許可しないのはなぜですか?
c++ - 菱形継承問題
私は菱形継承問題を経験していて、さまざまなシナリオでうまくいくと思いました。そして、これは私が取り組んでいたものの1つです。
MainBaseクラスのmainbase変数にアクセスする方法を知りたいですか?任意の入力。
c++ - 誤ってダイヤモンドを作成することを防ぐために、仮想継承を使用してもよいですか?
これは実際のコードを簡略化したものであり、誰かが既に Foo を実装し、そこから派生していることに気付いていなかったときに犯した本当の間違いです。
編集:このコードを実行する必要がないように...
- そのまま実行すると、「失敗」(望ましくない、デバッグが難しい) が出力されます。
- 「oops」とマークされた行を削除すると、「Foo」(望ましい動作) が出力されます。
- 「おっと」を残して 2 つの継承を仮想化すると、コンパイルされません (ただし、少なくとも何を修正すればよいかはわかっています)。
- 「oops」を削除して仮想化すると、コンパイルされて「Foo」が出力されます (望ましい動作)。
仮想継承を使用すると、結果は良好またはコンパイラ エラーになります。仮想継承がなければ、結果は良好であるか、説明がつかず、デバッグが困難な実行時障害になります。
Foo が既に行っていたことを基本的に複製する Bar を実装すると、動的キャストが失敗し、実際のコードでは問題が発生しました。
最初は、コンパイル エラーがないことに驚きました。次に、仮想継承がないことに気付きました。これにより、GCC で「一意の最終オーバーライド機能がありません」というエラーが発生しました。この設計にはひし形が含まれていないはずなので、意図的に仮想継承を使用しないことにしました。
しかし、Base から派生するときに仮想継承を使用していれば、コードは (おっともなく) 正常に機能し、コンパイル時にダイアモンドについて警告され、実行時にバグを追跡する必要があったはずです。
質問は、仮想継承を使用して将来同様の間違いを犯さないようにすることは許容できると思いますか? ここで仮想継承を使用する正当な技術的理由 (私にはわかります) はありません。設計にひし形があってはならないからです。その設計上の制約を強制するためだけに存在します。
c++ - ダイヤモンドの継承問題
楽しみのために、私は Windows 用の XUL 実装に取り組んでいます。XUL では、UI 要素は次のように XML で記述できます。
要素の属性を取得および設定するためのシステムを検討しています。それはかなりうまくいっていますが、ここでダイヤモンド継承の使用が潜在的に危険であるかどうかはわかりません. 以下に完全なコードサンプルを投稿しました。
基本クラスの Attributes にはデータ メンバーがないため、競合は発生しないので問題ないと思います。しかし、コミュニティに確認してみようと思いました。あなたの洞察は大歓迎です!
編集 「is-a」と「has-a」、および「継承よりも構成を優先する」という発言について、私はこれを言いたい:
- ここに継承の利点があります。Element が Width を継承する場合、getWidth メソッドと setWidth メソッドを実装する必要があります。したがって、属性を追加すると、Element のインターフェイスが「自動的に」更新されます。
- これらのクラスにはもともと AttributeController、WidthController、HeightController という名前を付けていましたが、冗長すぎることがわかりました。私の要素は属性コントローラーであると言えます。(わかりました、それは不自由ですが、真実ではありません!)
- さらなる証拠: Width と Height の定義にはデータ メンバーが含まれていません。Element クラスには実際にそれらがあります。Width クラスと Height クラスは、インターフェイスのみを提供します。だから、それはもっとできる関係です。
oop - ダイヤモンド問題
ダイヤモンド問題に関するウィキペディア:
「...ダイヤモンドの問題は、2つのクラスBとCがAから継承し、クラスDがBとCの両方から継承するときに発生するあいまいさです.DのメソッドがAで定義されたメソッドを呼び出す場合(およびメソッドをオーバーライドしない場合) )、そして B と C がそのメソッドを異なる方法でオーバーライドした場合、どのクラスから継承しますか: B または C?"
したがって、ダイヤモンドは次のようになります。
私の質問は、そのようなクラス A がなくても、B と C が同じメソッド、たとえば foo() を宣言するとどうなるかということです。これは同じ問題ではありませんか?なぜダイヤモンド問題と呼ばれるのですか?
例:
java - Java:この多重継承のあいまいさをどのように呼びますか?
これは、Javaで複数のインターフェースの継承を使用する例であり、問題があります。
なぜ問題があるのかを完全に理解していることに注意してください。これは私の質問のポイントではありません。問題は、この特定の複数のインターフェイスの継承のあいまいさについて、名前がある場合にどのように名前を付けるかについてです。
たとえば、C ++では、複数の実装継承を使用し、どのオーバーライドされたメソッドを使用するかを決定できない場合に発生するあいまいさは、「菱形継承問題」と呼ばれます。
http://en.wikipedia.org/wiki/Diamond_problem
繰り返しになりますが、これはここでは同じ問題ではないことを私は知っています。それは重要ではありません。重要なのは、その前のケースでは名前が造られているということです。
そして、これから説明する問題の名前が存在するかどうかを知りたいのですが。
別の種類の多重継承の例を次に示します。ここでは、1つのインターフェイスが、互換性のないメソッドの戻り型を持つ他の2つのインターフェイスから継承します。
(「extends」キーワードを使用して、複数のインターフェースの継承が機能していることに注意してください)
次の理由で、それを行うことはできません。
タイプAとタイプBは互換性がありません。どちらもc()を定義しますが、関連のない戻り型を使用します
その状況を説明するために名前が造られましたか?
c++ - ダイヤモンドを防ぐC++多重継承
C ++でクラスFooを定義して、次のようにする方法はありますか?
- 私はそれから継承することができます
- そこから「ダイヤモンド継承」できない
つまり
c++ - このダイヤモンド パターンに曖昧さがあるのはなぜですか?
これがダイヤモンド問題と呼ばれるかどうかはわかりませんが、なぜこれがうまくいかないのですか?
eat()
forの定義を与えましたD
。B
したがって、やのコピーを使用する必要はありませんC
(したがって、問題はないはずです)。
私が言ったとき、a->eat()
(remembereat()
は virtual ではないことを思い出してください)、eat()
呼び出すことができるのは の 1 つだけですA
。
では、なぜこのエラーが発生するのでしょうか。
「A」は「D」のあいまいなベースです
A *a = new D();
コンパイラにとって正確にはどういう意味ですか??
と
を使用すると同じ問題が発生しないのはなぜD *d = new D();
ですか?