class B
{
public:
int a;
void fn();
}
B のオブジェクトを作成すると、
B* pb = new B;
fn() のメモリはどこにありますか?
オブジェクトに fn() のメモリ位置を指すポインタはありますか?
はいの場合、オブジェクトにポインターがまったくないかのように sizeof(B) が値を返すのはなぜですか?
fn() のメモリはどこにありますか?
これは通常の関数であるため、プログラムのコード セクションのどこかにあります。この場所は、クラスのすべてのインスタンスで同じです。B
実際、 viaのインスタンス化とは何の関係もありませんpb
。
オブジェクトに fn() のメモリ位置を指すポインタはありますか?
いいえ。通常のメンバー関数の場合、アドレスはコンパイル時 (遅くともリンク時) にわかっているため、これは必要ありません。したがって、実行時に個別に保存する必要はありません。
仮想機能の場合、状況は異なります。仮想関数ポインタは配列に格納されます (「仮想関数ポインタ テーブル」または略して「vtable」と呼ばれます)。各クラスにはそのような vtable が 1 つあり、クラスの各インスタンスにはその vtable へのポインターが格納されます。型のポインタ/参照がBase
サブクラスを指しているDerived
場合、コンパイラはどの関数を呼び出すかを知る方法がないため、これが必要です。むしろ、関連する vtable で検索することにより、実行時に正しい関数が計算されます。vtable ポインターもsizeof
オブジェクトで明らかです。
これ:
class B
{
public:
int a;
void fn();
};
すべての実用的な目的で、C コードと同等です。
struct B
{
int a;
};
void fn(B* bInstance);
C++ バージョンを除いて、bInstance は this ポインターに置き換えられます。両方の関数のメモリがスタックに存在します。では、等価構造体に変換すると、sizeof(B) はどのようになると思いますか?
非仮想関数ではなく、仮想関数 (vtable 内) に対して格納されるポインターのみがあります。
1) B* pb = new B はヒープにメモリを割り当てます。つまり、特に、delete 演算子を使用して自分でクリーンアップする必要があります。または、ポインターをスマート ポインター (shared_ptr、auto_ptr、scope_ptr) 内に配置して、クリーンアップを実行させることもできます。
2) ポインターは型であるため、オブジェクトまたは null を指し、定義されたサイズ (通常は int に等しい) を持ちます。
3) fn() は仮想関数ではないため、オブジェクト内のメモリは vtable に割り当てられません。