0

I have a class D that extends B which extends A. I now want to add a class C that has exactly the same interface as B but provides a different implementation. So I design it as the following: diamond

This is not exactly what I want, as I only need an instance of D to either extend B or C and not both, however, this is only determined at runtime. The problem with the design above is of course that if I call a method in D which is implemented both in B and C, its ambiguous.

So what I would like to have is to create an instance of either B or C at runtime and then cast it into D. Every time an instance of D calls an inherited method it should use the one of its original object.

Do I need to fiddle with typeid and if/else around each method call or is there a more elegant way to do this?

class A{ 
virtual f1();
virtual f2();
}

class B : public virtual A{
f1();
f2();
f3();
}

class C : public virtual A{
f1();
f2();
f3();
}

class D : public B, public C{
f4(){f1(); f3)};
}

...
D* d = new D();
E* e = new E(d);
e->d->f1();
e->d->f4();

Instances of D are then passed to another class (E) which does stuff with D and therefore, I cannot modify the interface of D.

4

4 に答える 4

2

間違った方法で継承を行っていると思います。クラス D と呼ぶもので呼び出したいすべてのメソッドをクラス A の仮想メソッドとして定義し、クラス B と C の両方にそれらのメソッドの独自の実装があります。 .

次に、タイプ A* のデータ構造を使用し、タイプ B および C のオブジェクトへのポインタで埋め、タイプ A* のポインタを含むデータ構造内のすべてのオブジェクトで呼び出す必要があるメソッドを呼び出します。メカニズムは、実際のオブジェクトのタイプに応じて、クラス B または C の実装が使用されることを確認します。

具象クラスと抽象クラスの違いは何ですか? を参照してください。

于 2013-01-24T07:18:32.780 に答える
1

それはあなたが欲しいように聞こえます

class A{
    virtual void DoMagic() = 0;

};  
class B{
    virtual void DoMagic(){};

};  
class D{
    virtual void DoMagic(){};

};

...
bool INeedB = true;//or false
A* a;
if(INeedB){
    a= new B();
}else{
    a = new C();
}
a->DoMagic(); // will call the appropriate method based on the value of INeedB;

Dが実際に独自の動作を持っていない限り? 次に、デコレータ パターンを見て、D を B または C のインスタンスのデコレータにすることができます。

編集:あなたのクラスは、いずれかまたはDまったく継承する必要はありません。A BC

class D{
    D(A* aObj):a(aObj){}
    void f3(){ a->f1();a->f2();}
    A *a;
};

A *a上記の例を次のように置き換えますD d

于 2013-01-24T07:16:31.613 に答える
0

C++ は静的型付け言語です。型宣言で行うことはすべてコンパイル時に作成されるため、D実行時に継承グラフを定義することはできません。

おそらく必要なのはA、B と C (その具体的な実装) の両方のポリモーフィック ベース (関連するすべてのメソッド virtual、デストラクタを含む) として持つことと、D を「 an の所有者A」にすることです。 D コンストラクションで、new Bまたはnew C入力に応じて a に割り当てられます。

D デストラクタが を呼び出すdelete Aので、コピーと代入について決定する必要があります。

私の提案は、A* を使用するのではなく、std::unique_ptr(所有するオブジェクトを D 間で移動可能にする) またはstd::shared_ptr.

各 D に独自の A が必要な場合は、A にメソッドを持たせ(B と C でオーバーライドされ、それぞれ aとcloneを返す)、D の copy ctor と assign 演算子でそれを呼び出します。new Bnew C

于 2013-01-24T08:46:41.580 に答える
-1

(or or )Dから継承する必要はまったくないようです。代わりに、 のインスタンスまたは のインスタンスのいずれかで関数を呼び出すだけで済みます。ABCBC

次のように実装できます。

class A
{
public:
    virtual void f1();
    virtual void f2();
};

class B : public A;
class C : public A;

class D
{
   A* b_or_c;

public:
    D(A* a_pointer)
        : b_or_c(a_pointer)
        {}

    void f3()
        {
            b_or_c->f1();
            b_or_c->f2();
        }
};

次のように使用できます。

B b;  // An instance of B
C c;  // An instance of C

D d1(&b);
D d2(&c);

d1.f3();  // Will cause `f1` and `f2` in the object `b` to be called
d2.f3();  // Will cause `f1` and `f2` in the object `c` to be called
于 2013-01-24T07:17:05.827 に答える