6

4つのクラスがあるとします:

class I { public: virtual void X() = 0; };
class A : public virtual I { public: virtual void X() { } };
class B : public I {  };
class C : public A, public B { };

IBおよびCは抽象的ですが、asAはそうではありません。forvirtualの継承に単純に追加すると、 で解決されます。IBA::X()I::X()C

ただし、のソースを変更することはできませんB

私の質問:変更できずにA::X()解決I::Xできますか? 私は宣言して仮想化しようとしましたが、役に立ちませんでした。冗長なコードを持たないようにしています (たとえば、C に X() { A::X(); } を宣言させます)。きちんとしたハックはありますか?CBABC

virtualまた、これと非常によく似た質問がいくつかありますが、継承の使用について話しているものは見つかりませんでした。私がそれを逃した場合は、私に指摘してください。

4

3 に答える 3

3

あなたの問題はvtablesにあります。現在のコードでは、それらのうちの 2 つがあります。1 つは in でAIもう 1 つは inBですIA実質的に継承するだけである限り、I通常の継承を使用してオーバーヘッドを節約することもできます。両方が実質的に継承されている場合、 inIのインスタンスは 1 つしかないため、vtable は 1 つしかなく、実際に純粋な virtual をカバーできます。ICA::XI::X

を変更できない場合B、両方の vtable を処理できる唯一の場所は ですC。私の意見では、行く方法はあなたが言及したことです -C::Xに電話を転送してA::Xください。そこにはコードの重複はなく、C非抽象的になります:

class C : public A, public B {
public:
    virtual void X() { A::X(); }
};

仮想継承に関しては、間違いなくここにいくつかありました。でも、お気軽にお尋ねください...

于 2012-07-06T17:39:53.453 に答える
2

これはかなり良いです:仮想継承が優れた設計であるのはいつですか?

ここでの問題は、C には 2 つのインターフェース I があることです。これが、A::x() がそのインターフェース I を満たす理由ですが、クラス B から抽象インターフェース I を作成することはできません。C の場合、正確に 1 つのインターフェースを持つ唯一の方法は、 I - B を仮想的に I から派生するように変更することです。このようにして、A からの I インターフェイスと B からの I インターフェイスの両方が C のインターフェイスにマージされます。B を変更することはできません。したがって、唯一の方法は、試みているこの冗長コードを追加することです。避けるために。つまり、C::X() を定義します。

于 2012-07-06T17:40:09.963 に答える
1

私が考えることができる唯一の方法は、B*(またはスマート バリアント) をC継承する代わりに構成し、適切なメソッドを転送することです。継承を維持しながらそれを行うことはできません。これは、コンパイラーがI従うべき継承チェーンを認識できないためです。

于 2012-07-06T17:35:15.397 に答える