22

単一継承は実装が簡単です。たとえば、C では、継承は次のようにシミュレートできます。

struct Base { int a; }
struct Descendant { Base parent; int b; }

ただし、多重継承では、コンパイラは新しく構築されたクラス内に複数の親を配置する必要があります。それはどのように行われますか?

私が見ている問題は、両親がABまたはBAに配置されるべきか、それとも他の方法で配置されるべきかということです. そして、キャストを行うと:

SecondBase * base = (SecondBase *) &object_with_base1_and_base2_parents;

コンパイラは、元のポインターを変更するかどうかを検討する必要があります。バーチャルでも同様のトリッキーなことが必要です。

4

7 に答える 7

13

C++ の作成者による次の論文では、多重継承の可能な実装について説明しています。

C++ の多重継承- Bjarne Stroustrup

于 2009-06-16T16:15:39.763 に答える
5

VC++ での実装方法に関するこのかなり古い MSDN の記事がありました。

于 2009-06-16T16:13:55.083 に答える
5

そして、キャストを行うと:

SecondBase base = (SecondBase *) object_with_base1_and_base2_parents;

コンパイラは、元のポインターを変更するかどうかを検討する必要があります。バーチャルでの同様のトリッキーなこと。

非仮想継承では、これは思ったほど難しくはありません。キャストがコンパイルされる時点で、コンパイラは派生クラスの正確なレイアウトを認識します (結局のところ、コンパイラがレイアウトを行いました)。通常、発生するのは、固定オフセット (基本クラスの 1 つではゼロの場合があります) が派生クラス ポインターに加算/減算されることだけです。

仮想継承では、おそらくもう少し複雑です.vtbl(または同様のもの)からのオフセットを取得する必要があります。

Stan Lippman の著書「Inside the C++ Object Model」には、この機能がどのように機能するか (そして多くの場合実際に機能するか) が非常に適切に説明されています。

于 2009-06-16T16:44:10.657 に答える
1

親は、指定された順序で配置されます。

class Derived : A, B {} // A comes first, then B

class Derived : B, A {} // B comes first, then A

2 番目のケースは、コンパイラ固有の方法で処理されます。一般的な方法の 1 つは、プラットフォームのポインター サイズよりも大きいポインターを使用して、余分なデータを格納することです。

于 2009-06-16T16:16:20.403 に答える
1

これは、実際には C++ 固有ではない興味深い問題です。複数のディスパッチと複数の継承を持つ言語 (CLOS など) がある場合も、事態はさらに複雑になります。

人々は、問題にアプローチするさまざまな方法があることをすでに指摘しています。この文脈では、Meta-Object Protocols (MOP) について少し読むと興味深いかもしれません...

于 2009-06-16T16:24:57.673 に答える
0

それがどのように行われるかは完全にコンパイラ次第ですが、一般的には vtables の階層構造を通じて行われると思います。

于 2009-06-16T16:14:20.203 に答える