10

私はこの質問を読みました: C++ Virtual class inheritance object size issue、なぜ仮想継承がクラスに追加の vtable ポインターをもたらすのか疑問に思っていました。

ここで記事を見つけました: https://en.wikipedia.org/wiki/Virtual_inheritance

これは次のことを示しています。

ただし、このオフセットは通常、実行時にしかわかりません...

ここでランタイムに関連するものはわかりません。完全なクラス継承階層は、コンパイル時にすでにわかっています。仮想関数と基本ポインターの使用法は理解していますが、仮想継承にはそのようなものはありません。

一部のコンパイラ (Clang/GCC) が vtable を使用して仮想継承を実装する理由と、これが実行時にどのように使用されるかを誰かが説明できますか?

ところで、私はこの質問も見ました: vtable in case of virtual inheritanceですが、それは仮想関数に関連する回答のみを指しています。これは私の質問ではありません。

4

3 に答える 3

16

完全なクラス継承階層は、コンパイル時にすでにわかっています。

十分に真実です。そのため、コンパイラが最も派生したオブジェクトの型を知っている場合、そのオブジェクト内のすべてのサブオブジェクトのオフセットを知っています。このような目的では、vtable は必要ありません。

たとえば、BC両方が仮想的に から派生しA、 とがとDの両方から派生する場合、次のコードでは次のようになります。BC

D d;
A* a = &d;

D*からへの変換A*は、せいぜい静的オフセットをアドレスに追加するだけです。

ただし、次の状況を考慮してください。

A* f(B* b) { return b; }
A* g(C* c) { return c; }

ここでは、オブジェクトまたはその他の最も派生したクラス オブジェクトのサブオブジェクトである可能性があるオブジェクトを含む、f任意のオブジェクトへのポインターを受け入れることができなければなりません。をコンパイルするとき、コンパイラは の派生クラスの完全なセットを知りません。BBDfB

Bオブジェクトが最も派生したオブジェクトである場合、サブAオブジェクトは特定のオフセットに配置されます。しかし、Bオブジェクトがオブジェクトの一部である場合はどうなるDでしょうか? オブジェクトにはDオブジェクトが 1 つしか含まれておらず、とサブオブジェクトの両方Aから通常のオフセットに配置することはできません。したがって、コンパイラは のサブオブジェクトの場所を選択する必要があります。次に、 orを含むコードがサブオブジェクトの場所を見つけられるようにするメカニズムを提供する必要があります。これは、最も派生した型の継承階層のみに依存するため、vptr/vtable が適切なメカニズムです。BCADB*C*A

于 2019-08-13T18:07:45.563 に答える