2012-11-16 16 views
5

私はこのように見えるダイヤモンドの問題があります。複雑なダイヤモンドの問題:C++仮想継承

__ A 
/ |\ 
| B | \ 
v|/v v\|v \v 
B2 B3 C 
    \v /v /
    B4 /
    \ /
     D 

を私は重複を取得しないための最善の仮想継承を作るために多くの方法を試してみましたが、私は解決策を見つけることができませんでした。クラスAには位置が含まれています。ここに出力例があります:

Call: A() position pointer is: 0x2203be8 
Call: B() 
Call: B2() position pointer is: 0x2203be8 
Call: B3() position pointer is: 0x2203be8 
Call: C() position pointer is: 0x2203a28 
Call: B4() position pointer is: 0x2203be8 
Call: D() position pointer is: 0x2203a28 

なぜDとCの位置が同じではないのですか?なぜこのA :: positionのコンストラクタがないのですか?これを解決するために私はどのような仮想継承をすべきですか?ありがとう。

EDIT:

class A; 
class B; 
class B2 : public virtual B, public virtual A; 
class B3 : public virtual B, public virtual A; 
class C : public virtual A; 
class B4 : public virtual B2, public virtual B3; 
class D : public B4, public C; 

はEDIT 2:

はここでのサンプルコードの出力を行うために 、私はそれぞれのコンストラクタ内でこのコードを配置:

あなたは何のコード
A::A() 
{ 
    std::cerr << "Call: A() position pointer is: " << &_position << std::endl; 
} 
+4

これは恐ろしい外観のダイヤモンドです。 –

+0

ダイアモンド内のダイヤモンド! –

+0

使用している実際の継承関係を提供する必要があります。 1つの答えの形式を使用することを検討してください( 'derived_type:[virtual] base、[virtual] base2 ...')。どのように出力を生成しているのかを説明することも興味深いでしょう –

答えて

1

現在持っている?ソリューションは次のようになります:

class D; 
class C : public virtual D; 
class B4 : public virtual D; 
class B2 : public virtual B4; 
class B3 : public virtual B4; 
class B : public B2, public B3; 
class A : public B2, public B3, public C; 

図に基づいています。私はそれが間違って読んでいるとAがベースである場合、ないD.そして、それはこのように見える必要があります:

class A; 
class B; 
class B2 : public virtual B, public virtual A; 
class B3 : public virtual B, public virtual A; 
class C : public virtual A; 
class B4 : public virtual B2, public virtual B3; 
class D : public B4, public C; 
+0

oh!私にAを書いてみましょう。 – OmnipotentEntity

+1

もっと明白にするために、2番目のセットから欠落している唯一の '仮想'は 'D'のものです。 –

+0

2番目は良いコード –

0

はなぜDとCが位置のために同じポインタを持っていないのですか?

あなたはB4とCからDを実質的に継承していないので、A(と2つのポインタ)の2つのコピーがあることを意味します。 Dコンストラクタ& B4において

::このA ::位置にはコンストラクタがありませんなぜ位置& C ::位置

異なりますか?

あなたのAクラスに複数のコンストラクタがあり、デフォルトのサイレントコンストラクタがC :: C()によって呼び出される可能性はありませんか?

私はこれを解決するためにどのような仮想継承を行う必要がありますか?

すべて仮想化します。これは、D :: D()(つまりA :: A()、B :: B()、B2 :: B2()、B3 :: B3()、C ::からすべてのコンストラクタを明示的に呼び出す必要があることを意味します。 C())。

Tbh私はあなたの階層を再考すべきだと思います。私は詳細はわかりませんが、あなたの問題にはコンポーネント設計によるより洗練されたソリューションがあるようです。

+0

いいえ、私はAのコンストラクタが1つしかなく、Positionの2番目のポインタが初期化されていないようです –

+1

'B4'と' C'が非仮想的に継承されても、彼らは両方ともAのための仮想継承を使用するので、両方のための単一の 'A '。 「D」がどのように継承するかは関係ありません。また、 'D 'のすべてのコンストラクタを明示的に呼び出す必要はありません。 – bames53

4

私の実装で動作する以下のコードはあなたにとって壊れていると言うので、明らかにコードは問題ではありません。問題は、あなたの設定で他に何かがあることです。おそらくコンパイラのバグです。問題の原因となるものを絞り込む必要があります。コード自体が問題として除外されている可能性があるため、おそらく次のステップはコンパイラを更新することです。

いずれにしても、あなたの設定に固有の質問です。あなたが他の人に適用されるかもしれない解決策を見つけたら、あなたは戻ってそれを投稿するべきです。それまで私はこの質問を閉じることに投票しています。


問題を再現しようとしています。

#include <iostream> 

struct A { int a; }; 
struct B { int b; }; 
struct B2 : virtual B, virtual A {}; 
struct B3 : virtual B, virtual A {}; 
struct B4 : virtual B2, virtual B3 {}; // these virtuals are unnecessary in this case... 
struct C : virtual A {}; 
struct D : B4, C {}; 

int main() { 
    D d; 
    std::cout << &((B4*)&d)->a << '\n'; 
    std::cout << &((B3*)(B4*)&d)->a << '\n'; 
    std::cout << &((B2*)(B4*)&d)->a << '\n'; 
    std::cout << &((A*)(B2*)(B4*)&d)->a << '\n'; 
    std::cout << &((A*)(B3*)(B4*)&d)->a << '\n'; 
    std::cout << &((C*)&d)->a << '\n'; 
    std::cout << &((A*)(C*)&d)->a << '\n'; 
} 

をしかし、予想通りaメンバーはすべてのオブジェクトに対して同じであるところ私が得る結果は、以下のとおりです。ここで私が使用しているコードです。私はわずかな変更を行う場合はhttp://ideone.com/8FdQ1O

をし、Cの定義からvirtualキーワードを削除:

... 
struct C : A {}; 
... 

version using constructors

私もコンストラクタ内のアドレスをプリントアウト使用している場合、私は同じ結果を得ます

私は、Cがそれ自身のものであることを記述する問題を見ています.B2、B3、およびB4によって使用される仮想オブジェクトとは異なるサブオブジェクトです。

virtualキーワードは、必要なすべての場所で使用していますか?表示された結果は、あなたがどこかでそれを見逃していることを示しているようです。また、表示される出力は、表示するコードフラグメントと同じコンストラクタの順序を反映していないことにも注意してください。出力は最初にA()を示しますが、コードはB()が最初に実行されるべきであることを示します。


仮想継承が機能する方法は、ほとんどの派生型が事実上継承ツリー内のどこにでも継承されているタイプごとに単一の仮想サブオブジェクトが含まれているということです。さらに、ほとんどの派生型は、非仮想継承のインスタンスごとにサブオブジェクトが含まれます。

struct A {}; 
struct B : virtual A {}; 
struct C : A, B {}; 
struct D : virtual A, C {}; 
struct E : A, D {}; 
struct F : virtual A, E {}; 
struct G : A, F {}; 

G g; 

gは、4つのAサブオブジェクトの合計を含んでいます。各時間Aための1つの非実質(CE、及びGで)継承され、そして一度回Aの全てに対して実質(BD、及びFに)継承されます。

+0

残念ながら、私は必要なすべての仮想キーワードを追加しましたが、私はまだバグを取得します。私は4.6.3を使用しました –

+0

@GuillaumeRacicotあなたはプログラムを実行したときに私はあなたが問題を見ていたと言っていますか?あるいは、コードをどうにか変更しましたか?すでに提供されているフラグメントには問題の原因が含まれていないように見えるため、誰でも問題を診断できるように、実際のコードを十分に用意しなければなりません。 – bames53

+0

あなたが私に送ったプログラムはまったく同じものでした。問題は、私が働いているものと同じコードを持っていることです... –