5

仮想関数を含む仮想継承の場合のクラスのサイズについて誰か説明してもらえますか?

   class A{
          char k[ 3 ];
          public:
          virtual void a(){};
          };

   class B : public  A{
          char j[ 3 ];
          public:
          virtual  void b(){};
          };

   class C : public virtual A{
          char i[ 3 ];
          public:
          virtual void c(){};
          };

   class D : public B, public C{
          char h[ 3 ];
          public:
          virtual void d(){};
          };

クラスのサイズの出力は次のとおりです。

    sizeof(A): 8
    sizeof(B): 12
    sizeof(C): 16
    sizeof(D): 32

私が使用しているコンパイラは gcc version 4.6.1 (Ubuntu/Linaro 4.6.1-9ubuntu3)

4

4 に答える 4

7

sizeof(A):8

配列内に3バイト、1バイトのパディング、vptr用に4バイト(vtableへのポインター)

sizeof(B):12

サブオブジェクト:8、追加の配列用に3バイト、1バイトのパディング

sizeof(C):16

これはおそらくあなたにとって驚くべきものです...サブオブジェクト:8、追加の配列用の3バイト、1バイトのパディング、Aへの4バイトのポインタ

仮想継承がある場合は常に、完全な型の開始に対する仮想ベースサブオブジェクトの位置が不明であるため、仮想ベースがどこにあるかを追跡するために、元のオブジェクトに追加のポインターが追加されます。この例を考えてみましょう。

struct A {};
struct B : virtual A {};
struct C : virtual A {};
struct D : B, C {};

完全なタイプがaである場合Aのオブジェクトの開始に対するの位置は、それが最終オブジェクトの一部である場合のサブオブジェクトの位置とは異なる場合があります。これが明らかでない場合は、相対位置が同じであると想定し、の最終オブジェクトまたはサブオブジェクトの相対位置も維持できるかどうかを確認します。BBABDACCCD

最後の例については、分析する気がしません...しかし、C++オブジェクトモデルの具体的な実装についてはItaniumC++ABIを読むことができます。他のすべての実装はそれほど違いはありません。


最後の例:

sizeof(D):32

Dには、Bサブオブジェクト(12)とCサブオブジェクト(16)に加えて、サイズ3の追加の配列と1ビットのパディング1が含まれています。

この特定のケースでは、仮想的に継承するA場合に2つのサブオブジェクトが存在するのはなぜかという疑問が生じます。その答えは、仮想ベースとは、オブジェクトがこのベースを階層内の他のタイプと共有することを意味するということです。それを共有します。ただし、この場合、そのサブオブジェクトを共有することをいとわないため、独自のサブオブジェクトが必要です。CABAC

さまざまなレベルのコンストラクターにログを追加することで、これを追跡できるはずです。Aコンパイラで値を取得し、各拡張クラスから異なる値を渡す場合。

于 2012-05-10T20:31:06.523 に答える
1

sizeof(C)タイプCのオブジェクト(実質的にAから継承しているsizeof(B)ため)には、Aから継承した自身の部分を指すポインター(タイプBのオブジェクトも含むvptrは別として)が含まれるためです。ScottMeyersこれについては、項目24で詳しく説明しています(約10ページ)。「仮想関数、多重継承、仮想基本クラス、およびRTTIのコストを理解する」彼の著書「より効果的なC++ 」

于 2012-05-10T20:10:36.433 に答える
0

データ構造の実際のサイズを知るには、#pragma pack(1)を使用して、データ構造をメモリ内で整列させないようにコンパイラーを指定できます。現在のパッキング設定を保存して後で復元するには、#pragma pack(push)および#pragma pack(pop)を使用することもできます。

于 2012-05-10T20:23:52.810 に答える
-1

すべてのバイトが使用されている場所についての私の最善の推測は次のとおりです。

              Avptr Bvptr CVptr DVptr k j i h k' j' i'  TOTAL
============= ========================================= =====
sizeof(A): 8    4                     4                   8
sizeof(B): 12        4                4 4                12
sizeof(C): 16              4          4 4 4              16
sizeof(D): 32                    4    4 4 4 4  4  4  4   32

どこ:

  • vptrsはそれぞれ4バイトを使用します(64ビットポインター)
  • char配列はそれぞれ4バイトかかります(整列のために切り上げられます)
  • k'、j'、およびi'は、BではなくCを介して継承される変数のコピーです。
于 2012-05-10T20:15:44.967 に答える