... 注意してください、Herb Sutter は、多重継承に関する 3 つの優れた記事(1) ここ、(2) ここ、および(3) ここを書きました。彼はここの週の第一人者に有益な記事をたくさん書いています。強くお勧めします ...
まず、あなたの階層が正しいかどうかわかりません。私はそれが次のようなものだと思います:
struct A {
virtual void F() = 0;
};
struct B : A { void F() { } };
struct C : A { };
struct D : B, C { };
AD型のオブジェクトには 2 つのサブオブジェクトがあるため、D は抽象的です。1 つBは B のラティスを介して具体化され、もう 1 つは を通過するラティス内でまだ抽象的Cです。私はあなたがポインタを持っていると思い、Dを呼び出そうとしますF。はい、あいまいさが生じます。これは、コンパイラが 2Fつの別個のラティスで 2 つの関数を検出するためです。
D -> B::F
D -> C -> A::F
次のようになります。
F() F()
A A
| |
F() B C
\ /
D
A から仮想的に導出することで、その状況を正式に修正できます。
struct B : virtual A { void F() { } };
struct C : virtual A { };
struct D : B, C { };
次に、ダイヤモンド継承と呼ばれるこの状況があります。
F()
A
/ \
F() B C
\ /
D
B::Fルックアップを行うと、オーバーライドがあることがわかりますA::F。A::Fを介して到達することはできますが、継承された virtualD::C::Aであるため、これはもはやあいまいではありません。A
これが特定の問題の正しい解決策であるかどうか-もちろん、それは確かではありません。ほとんどの場合、クラスから virtual を派生させるよりも優れた方法があります。仮想関数テーブルのマージに関する質問に対して - それは実装に完全に依存しています。GCCは、私が知る限り、virtualDを導出すると、 の仮想テーブル内の 1 つの A インスタンスへのポインタを保持します。