仮想ベースオブジェクトは、オブジェクトに属するメモリブロックのどこかにあります(size = sizeof(object)のメモリ)。異なるタイプの複数のサブオブジェクトはさまざまな方法で組み合わせることができますが、同じベースオブジェクトを共有する必要があるため、仮想ベースオブジェクトを見つけるには、各サブオブジェクトにオフセットポインタが必要です。仮想継承がない場合、対応するベースオブジェクトを見つけるためのオフセットは、各クラスタイプのコンパイル時に固定されます。
sizeof値はコンパイラとマシンによって異なりますが、次の仮定は非常に一般的です。
仮定:ポインタサイズは4バイトです
仮定:クラスサイズは4バイトの倍数に切り上げられます
sizeof(A): 8 -> 1 pointer to vtable (virtual method)
+ 3 chars -> 4+3=7
-> round up to 8
sizeof(B): 20 -> 8 + 1 pointer to vtable (virtual method)
+ 1 offset pointer to virtual base
+ 3 chars -> 8 + 4 + 4 + 3 = 19
-> round up to 20
sizeof(C): 32 -> 20 + 1 pointer to vtable (virtual method)
+ 1 offset pointer to virtual base
+ 3 chars
-> 20 + 4 + 4 + 3 = 31 // this calculation refers to an older
-> round up to 32 // version of the question's example
// where C had B as base class
実際の計算はコンパイラがどのように機能するかを正確に知っている必要があるため、計算は推測されます。
よろしく、オリバー
追加のオフセットポインタが必要な理由の詳細:
例:
class B : virtual public A {...};
class C : virtual public A {...};
class D1 : public B {...};
class D2 : public B, C {...};
D1の可能なメモリレイアウト。
A
B
D1
D2の可能なメモリレイアウト:
A
C
B
D2
2番目のケースでは、サブオブジェクトBは、そのベースAを見つけるために別のオフセットが必要です。
タイプD2のオブジェクトは、すべての親オブジェクト部分が含まれるメモリブロックで構成されます。つまり、タイプD2のオブジェクトのメモリブロックには、Aメンバー変数、Cメンバー変数、Bメンバー変数、およびD2メンバー変数。これらのセクションの順序はコンパイラに依存しますが、この例は、複数の仮想継承の場合、オブジェクトの合計メモリブロック内 で仮想ベースオブジェクトを指すオフセットポインタが必要であることを示しています。これが必要なのは、クラスBのメソッドがBへのこのポインターを1つだけ知っており、Aメモリ部分がこのポインターに対してどこにあるかを何らかの方法で計算する必要があるためです。
(D)の計算サイズ:
sizeof(D): 36 -> A:3 chars + A:vtable
+ B:3 chars + B:vtable + B:virtual base pointer
+ C:3 chars + C:vtable + C:virtual base pointer
+ D:3 chars + D:vtable
= 3 + 4
+ 3 + 4 + 4
+ 3 + 4 + 4
+ 3 + 4
= 36
上記の計算はおそらく間違っています;-)..。
D部分に独自のvtableポインターがあるかどうかはわかりません(これはすべてコンパイラーに大きく依存します)。
D部分がその親クラスのvtableポインターエントリを使用し、各部分の整列に4バイトの追加バイトが使用されている可能性があると思います(8バイトの倍数)。
したがって、この計算はおそらくより正確です。
sizeof(D): 36 -> A:3 chars + A:vtable + A:alignment
+ B:3 chars + B:vtable + B:virtual base pointer + B:alignment
+ C:3 chars + C:vtable + C:virtual base pointer + C:alignment
+ D:3 chars + D:alignment
= 3 + 4 + 1
+ 3 + 4 + 4 + 1
+ 3 + 4 + 4 + 1
+ 3 + 1
= 36