私はC++オブジェクトモデルの内部の本を読んでいます。この本には、次のような例があります。
struct Base1
{
int v1;
};
struct Base2
{
int v2;
};
class Derived : public Base1, public Base2 {};
printf("&Derived::v1 = %p\n", &Derived::v1); // Print 0 in VS2008/VS2012
printf("&Derived::v2 = %p\n", &Derived::v2); // Print 0 in VS2008/VS2012
前のコードでは、アドレスDerived::v1とDerived::v2の出力は両方とも0になります。ただし、変数を介して同じアドレスを出力する場合:
int Derived::*p;
p = &Derived::v1;
printf("p = %p (&Derived::v1)\n", p); // Print 0 in VS2008/VS2012 as before
p = &Derived::v2;
printf("p = %p (&Derived::v2)\n", p); // Print 4 in VS2008/VS2012
&Derived :: v1とpのサイズを調べると、両方で4になります。
// Both are 4
printf("Size of (&Derived::v1) is %d\n", sizeof(&Derived::v1));
printf("Size of p is %d\n", sizeof(p));
Derived :: v1のアドレスは0になりますが、Derived::v2のアドレスは4になります。変数に割り当てたときに&Derived::v2が4になった理由がわかりません。
アセンブリコードを調べます。Derived::v2のアドレスを直接クエリすると、0に変換されます。ただし、変数に割り当てると、4に変換されます。
VS2008とVS2012の両方でテストしましたが、結果は同じです。ですから、マイクロソフトにそのようなデザインを選ばせるには、何らかの理由があるに違いないと思います。
そして、あなたがこれを好きなら:
d1.*(&Derived::v2) = 1;
どうやら&Derived::v2は0ではありません。コンパイラがこの2つのケースを区別するのはなぜですか?
誰かがその背後で起こっていることを教えてもらえますか?ありがとうございました!
- 編集 -
&Derived::v1が有効なアドレスを取得していないと思う人のために。あなたはこれをしたことがありませんか?
Derived d1, d2;
d1.*p = 1;
d2.*p = 1;