0

通常のひし形パターンがあるとします。

class A
{
public:
    virtual char foo() = 0;

    virtual ~A() {} 
};

class B :  public A
{
public:
    virtual char foo() { return 'B';}

    virtual ~B() {}
};

class C :  public A
{
public:
    virtual char foo() { return 'C';}

    virtual ~C() {}
};

class D :  public B,  public C
{
public:

    virtual char foo() { return 'D';}

    virtual ~D() {}
};

A基本クラスにはデータ メンバーがないことに注意してください。実際には、純粋な仮想メソッドを備えたインターフェイスにすぎません。

今私がする場合:

D* d = new D();

A* a = static_cast<A*>(d);

コンパイラは、2 つの A 基底クラスがあるため、キャストがあいまいであることを教えてくれます。

しかし、もし私がそうしたらどうしますか:

D* d = new D();

B* b = static_cast<B*>(d); // Or C* c = static_cast<C*>(d); 

A* a = static_cast<A*>(b);

Aこれで、基本クラスの 1 つへのポインターがあり、実行できますa->foo()

これは安全ですか?

私が知りたいのは、この二重アップキャストを実行して、仮想継承のオーバーヘッドなしでインターフェイスへのポインター (データメンバーなし) を持つことができるかどうかです。とにかくポインターをダウンキャストしたり、仮想メソッドを呼び出していない何かをしたりするつもりはありません。

これは 2 つの基本クラスを持つことを意味することはわかっていますが、メンバーがないので問題にならないのでしょうか。

EDIT: インターフェイスを実装する方法を見つけるのに苦労しています。仮想継承を使用する必要があると思います。

クラスBuffer(インターフェースクラス)と、BufferImplementationそこから派生したクラスがあるとします。

ここで、 と インターフェイスの両方から派生する必要があるクラスを持つ別のインターフェイスIOBuffer(他のインターフェイスから派生する) があるとします。BufferIOBufferImplementationBufferImplementationIOBuffer

前の例では、Buffer は A、BufferImplementation は B、IOBuffer は C、IOBufferImplementation は D です。

4

2 に答える 2

0

あなたが書いたものはダイヤモンドパターンではありません!

これをダイヤ柄にするならvirtual inheritコレ!

class B :  virtual public A

class C :  virtual public A

あなたのバージョンは基本クラスから単純に線形に派生するため、D には基本クラス A の 2 倍が含まれます。その結果、コンパイラは、要求された場合にどの A を選択する必要があるかを知る機会がありません。virtual で導出すると、D で A が 1 つだけ得られます。

A のコンストラクター in D を手動で呼び出す必要があることに注意してください。また、C または D のコンストラクターが A のコンストラクターを呼び出す場合も! D! のインスタンスを作成すると、この呼び出しは発生しません。

于 2014-05-10T13:13:21.257 に答える