3

多重継承における C++ のオブジェクト レイアウトを理解しようとしています。この目的のために、2 つのスーパークラス A、B、および 1 つのサブクラス C を用意しました。A のフィールド | vfptr | B のフィールド | Cのフィールド。

このモデルを取得しましたが、理解できないゼロがいくつかあります。これが私が試しているコードです

    #include <iostream>

    using namespace std;

    class A{
       public:
       int a;
       A(){ a = 5; }
       virtual void foo(){ }
    }; 

    class B{
       public:
       int b;    
       B(){ b = 10; }
       virtual void foo2(){ }
    };

    class C : public A, public B{
       public:
       int c;    
       C(){ c = 15; a = 20;}
       virtual void foo2(){ cout << "Heeello!\n";}
    };

   int main()
  {
    C c;
    int *ptr;

ptr = (int *)&c;
cout << *ptr << endl;
ptr++;
cout << *ptr << endl;
ptr++;
cout << *ptr << endl;
ptr++;
cout << *ptr << endl;
ptr++;
cout << *ptr << endl;
ptr++;
cout << *ptr << endl;
ptr++;
cout << *ptr << endl;
ptr++;
cout << *ptr << endl;
ptr++;
cout << *ptr << endl;

       return 0;
   }

そして、ここに私が得る出力があります:

4198384     //vfptr
0
20          // value of a
0
4198416     //vfptr
0
10          // value of b
15          // value of c

間のゼロの意味は何ですか? 前もって感謝します!

4

6 に答える 6

2

これはアーキテクチャとコンパイラに大きく依存します...おそらく、ポインタのサイズはintのサイズではないかもしれません...どのアーキテクチャ/コンパイラを使用していますか?

于 2014-02-09T20:07:09.867 に答える
2

64 ビット システムで作業している場合は、次のようにします。

  • 最初の 0 は、最初の の最上位 4 バイトですvfptr

  • 2 番目のゼロはパディングであるため、2 番目vfptrは 8 バイトのアドレスにアラインされます。

  • 3 番目のゼロは、2 番目の 4 つの最上位バイトですvfptr

sizeof(void*) == 8それを主張するためにかどうかを確認できます。

于 2014-02-09T20:07:40.733 に答える
2

それはコンパイラに依存します。clang-500 を使用すると、次のようになります。

191787296
1
20
0
191787328
1
10
15
1785512560

GDBの方法もあると確信していますが、クラスオブジェクトのアドレスにLLDBを使用してポインターサイズの単語をダンプすると、次のようになります。

0x7fff5fbff9d0: 0x0000000100002120 vtable for C + 16
0x7fff5fbff9d8: 0x0000000000000014
0x7fff5fbff9e0: 0x0000000100002140 vtable for C + 48
0x7fff5fbff9e8: 0x0000000f0000000a

このレイアウトは理にかなっているようですね。まさにあなたが期待するもの。デバッガーのようにプログラムできれいに表示されない理由は、int サイズの単語をダンプしているためです。64 ビット システムでは sizeof(int)==4 ですが sizeof(void*)==8

したがって、ポインターが (int,int) ペアに分割されていることがわかります。Linux では、ポインターに下位 32 を超えるビットが設定されていません。OSX ではポインターが設定されています。したがって、0 対 1 の不一致の理由

于 2014-02-09T20:04:27.480 に答える
1

プラットフォームとコンパイラを知らずに判断するのは難しいですが、これはアラインメントの問題である可能性があります。実際、コンパイラは、パディングにゼロを使用して、8 バイト境界に沿ってクラス データを整列させようとする場合があります。

上記の詳細がなければ、これは単なる憶測です。

于 2014-02-09T20:03:21.090 に答える
1

これは、コンパイラ、システム、ビット数に完全に依存しています。

仮想テーブル ポインターは、ポインターのサイズになります。これは、ファイルを 32 ビットまたは 64 ビットのどちらでコンパイルしているかによって異なります。ポインターも、そのサイズの複数のアドレスに配置されます (通常の型と同様)。の後に 0 のパディングが表示されるのは、おそらくこれが理由です20

整数は、特定のシステムの整数のサイズになります。通常、これは常に 32 ビットです。これがマシンに当てはまらない場合、ポインター演算で sizeof(int) によって ptr を増やしているため、予期しない結果が生じることに注意してください。

于 2014-02-09T20:10:20.453 に答える