データ メンバーを持たないクラスのサイズは、暗黙の 'this' ポインターが宣言されていても、1 バイトとして返されます。返されるサイズは 4 バイト (32 ビット マシン上) であるべきではありませんか? 「this」ポインターはオブジェクトのサイズを計算するためにカウントされないことを示す記事に出くわしました。しかし、私はこの理由を理解することができません。また、メンバー関数が仮想として宣言されている場合、クラスのサイズは 4 バイトとして返されるようになりました。これは、オブジェクトのサイズを計算するために vptr がカウントされることを意味します。オブジェクトのサイズを計算する際に vptr が考慮され、'this' ポインターが無視されるのはなぜですか?
4 に答える
this
ポインターはクラスのメンバーではありません。これは、現在のインスタンスを参照するためにクラスに属するメソッドで使用される単なる構成です。
このようなクラスがある場合:
class IntPair
{
public:
IntPair(int a, int b) : _a(a), _b(b) { }
int sum() const { return _a + _b; }
public:
int _a;
int _b;
};
このクラスは、int
インスタンスごとに 2 つのインスタンスのためのスペースのみを必要とします。インスタンスを作成してメソッドを実行するとsum()
、そのメソッドはインスタンスへのポインターで呼び出されますが、そのポインターは常に別の場所から取得され、オブジェクト インスタンスには格納されません。
例えば:
IntPair *fib12 = new IntPair(89, 144);
cout << fib12->sum();
this
ポインターになる変数が、オブジェクトを作成したスコープ内のオブジェクトの外側に格納されていることに注意してください。
実際、上記のようなメソッドは常に次のように変換できます。
static int sum2(const IntPair* instance)
{
return instance->_a + instance->_b;
}
上記がクラス内で定義されている場合(プライベートメンバーにアクセスできるため)、違いはありません。実際、これはメソッドが舞台裏で実装される方法です。ポインターは、this
すべてのメンバー メソッドに対する単なる隠し引数です。
呼び出しは次のようになります。
IntPair* fib12 = new IntPair(89, 144);
cout << IntPair::sum2(fib12);
「this」はデータ メンバーとしてクラスに保存されません。クラスのインスタンスへの「ポインタ」にすぎません。メソッドに渡される「隠し引数」と考えてください。実際、Win32 システムでは、ecx レジスターで渡されることがよくあります (最初に考えた eax ではありません)。
仮想メソッドが 1 つ以上あるとすぐに、アプリケーションには仮想メソッドへのポインターを格納する方法が必要になります。これは vtable と呼ばれ、同じクラスのすべてのインスタンスで同一です。実行時に、どの「仮想メソッド」に対してどの「明示的な」メソッドを呼び出すかを知る必要があるため、vtable へのポインターがクラス インスタンスに格納されます。したがって、vtable-pointer (または vptr) には 4 バイト (または 64 ビット システムでは 8 バイト) が必要です。
this ポインターはオブジェクト内に格納されません。その必要はありません。関数を呼び出すためのポインターまたはオブジェクトが既にあります。1 のサイズに関しては、C++ 標準では、個別のオブジェクトには個別のアドレスが必要です。
ポインタのサイズは、常にメモリに格納する必要のあるポインタのタイプのサイズです。
たとえば、intのメモリアドレスが64ビットアーキテクチャで32ビットの場合、
int a = 10; int * b =&a; sizeof(b); // 32 sizeof(&b); 64