クラスのメモリへの割り当ての問題
メンバー変数:静的と非静的の区別;メンバー関数には、静的、非静的、虚的の3つがあります.では、これらのものはメモリにどのように割り当てられているのでしょうか.1つの例で説明します.
{
public:
static int a;
CObject();
~CObject();
void Fun();
private:
int m_count;
int m_index;
};
これは私のテストコードです.実行結果は:Sizeof(CObject):8 CObject::a=1 Construct! sizeof(myObject):8 sizeof(int)4 Destruct!疑問なのは、(1)C++では、対象になってこそメモリ領域が割り当てられるのではないでしょうか.?なぜCObjectメモリサイズは8なのか、ちょうど2つのメンバー変数の大きさの和と一致しているのか.インスタンス化されていないうちにクラスにメモリ領域があるのか.(2)オブジェクトが生成されたとき、算出されたメモリサイズはどのように8なのか、関数はメモリ領域を占有しないのか.少なくとも関数ポインタを入れておくべきではないか.メモリはどのように配置されているのか.(3)静的メンバーはクラスに属しているはずだが、どのようなクラスのサイズに静的メンバーのサイズが含まれていないのか.以下、それぞれ1)Sizeof(CObject)コンパイル時に計算されたクラス定義で、そのメモリコンパイラはすでに知っています.この場合、その使用サイズを得るだけで、メモリ操作は割り当てられません.コンパイラはサイズを知っているに違いない.これはメモリ領域の割り当てとは関係なく、サイズを知っている.後でインスタンス化してこそ、割り当ての大きさを知ることができる.2)クラスの普通のメンバー関数、静的メンバー関数はクラスのメモリを占めません.あなたが言った関数ポインタがあなたのクラスに虚関数がある場合、虚関数テーブルポインタが存在します.つまり、あなたのクラスに虚関数がある場合、sizeof(CObject)の値は4つのワードを増加します.実はクラスのメンバー関数は実際には普通のグローバル関数と同じです.ただし、コンパイラはコンパイル時にメンバー関数にパラメータを追加し、このオブジェクトのポインタを渡します.メンバー関数アドレスはグローバルに既知であり、オブジェクトのメモリ領域にメンバー関数アドレスを保存する必要はありません.メンバー関数(非虚関数)の呼び出しは、コンパイル時に決定されます.myobjectのようにFun()のような呼び出しは、次のようにコンパイルされます.CObject_Fun(&myObject)の様子.関数はsizeofには含まれません.関数はコードなので、各オブジェクトに共用され、データ処理方式とは異なります.オブジェクトに関数ポインタがある必要はありません.オブジェクトはその各関数のアドレスを知る必要がないため(関数を呼び出すのは他のコードであって、そのオブジェクトではありません).クラスの属性はクラスのデータメンバーを指し、1つのオブジェクトをインスタンス化するとデータメンバーにメモリが割り当てられ、各オブジェクトのデータメンバーは対立し、メンバー関数は共通~静的メンバー関数と一般メンバー関数の唯一の違いはthisポインタがないため、非静的データ・メンバー.要するに,プログラム内のすべての関数はコード領域に位置する.3)静的メンバーはオブジェクトに属しておらず,sizeofはオブジェクトサイズをとる.上のことがわかったら、直してみてもいいです.class CObject{public:static int a;CObject();~CObject();void Fun();private:double m_count;//ここでdouble int m_indexに変更しました. };このクラスでsizeof()で測定したサイズは2*sizeof(double)=16 class CObject{public:static int a;CObject();~CObject();void Fun();private:char m_count;//ここでchar int m_indexに変更しました. };サイズは2*sizeof(int)=8 class CObject{public:static int a;CObject();~CObject();void Fun();private:double m_count;//ここでdouble int m_index;char c; };sizeof(char)+sizeof(int)まず、空のクラスがどれだけの空間を占めているかを見てみましょう.
class Base {
public: Base();
~Base();
};
class Base { public: Base(); ~Base(); };
ここでは構造と解析が宣言されていることに気づいたがsizeof(Base)の結果は1.
空のクラスもインスタンス化されるため、クラスのインスタンス化とはメモリにアドレスを割り当て、各インスタンスにはメモリにユニークなアドレスが割り当てられます.同じように空クラスもインスタンス化されるので、コンパイラは空クラスに隠しバイトを追加し、空クラスがインスタンス化されるとユニークなアドレスが得られます.したがって、空のクラスのsizeofは1です.
構造関数は、構造関数などのメンバー関数とはsizeofとは関係なく、私たちのsizeofはインスタンスに対して、普通のメンバー関数は、クラス体に対して、1つのクラスのメンバー関数で、複数のインスタンスも同じ関数ポインタを共有しているので、自然にインスタンスの大きさに帰すことはできません.これは私の別のブログで述べています.
次のコードを見てください
class Base {
public: Base();
virtual ~Base();//各インスタンスに虚関数テーブルがある void set_num(int num)/一般メンバー関数、各インスタンスに公有、sizeof統計 に帰属しない
{ a=num;
} private:
int a;//4バイト char *p;//4バイトポインタ };
class Derive:public Base {
public: Derive():Base(){};
~Derive(){}; private:
static int st;//非インスタンス排他 int d;//4バイト char *p;//4バイトポインタ
};
int main() {
cout< cout<
return 0; }
結果は自然に
12
20
ベースクラスのint a;char *p;8バイトを占めます.
虚析構造関数virtual~Base()のポインタは4サブバイトです.
他のメンバー関数はsizeof統計に含まれません.
Deriveクラスは、まずBaseクラスの部分、つまり12バイトを持つ必要があります.
int d;char *p;8バイトを占める
static int st;sizeof統計に戻さない
だから全部で20バイトです.
Deriveにメンバーchar cを追加することを考えています.
class Derive:public Base {
public: Derive():Base(){};
~Derive(){}; private:
static int st; int d;
char *p; char c;
};
この時、結果は
12
24
1つのchar c;4バイト増加し、クラスのサイズもclassバイトの整列のような補完ルールを遵守していることを示します.
具体的には私の「5分でバイトの位置合わせができます」を見ることができます.
ここで、以下の原則をまとめることができます.
1.クラスのサイズは、クラスの非静的メンバーデータのタイプサイズの和であり、つまり静的メンバーデータは考慮されない.
2.一般メンバー関数はsizeofとは無関係です.
3.ダミー関数は、ダミー関数テーブルに維持されるため、ポインタサイズ、すなわち4バイトを占有します.
4.クラスの合計サイズもclassバイトのように整列し、ルールを調整します.
class CObject {
public:
static int a;
CObject();
~CObject();
void Fun();
private:
int m_count;
int m_index;
};
これは私のテストコードです.実行結果は:Sizeof(CObject):8 CObject::a=1 Construct! sizeof(myObject):8 sizeof(int)4 Destruct!疑問なのは、(1)C++では、対象になってこそメモリ領域が割り当てられるのではないでしょうか.?なぜCObjectメモリサイズは8なのか、ちょうど2つのメンバー変数の大きさの和と一致しているのか.インスタンス化されていないうちにクラスにメモリ領域があるのか.(2)オブジェクトが生成されたとき、算出されたメモリサイズはどのように8なのか、関数はメモリ領域を占有しないのか.少なくとも関数ポインタを入れておくべきではないか.メモリはどのように配置されているのか.(3)静的メンバーはクラスに属しているはずだが、どのようなクラスのサイズに静的メンバーのサイズが含まれていないのか.以下、それぞれ1)Sizeof(CObject)コンパイル時に計算されたクラス定義で、そのメモリコンパイラはすでに知っています.この場合、その使用サイズを得るだけで、メモリ操作は割り当てられません.コンパイラはサイズを知っているに違いない.これはメモリ領域の割り当てとは関係なく、サイズを知っている.後でインスタンス化してこそ、割り当ての大きさを知ることができる.2)クラスの普通のメンバー関数、静的メンバー関数はクラスのメモリを占めません.あなたが言った関数ポインタがあなたのクラスに虚関数がある場合、虚関数テーブルポインタが存在します.つまり、あなたのクラスに虚関数がある場合、sizeof(CObject)の値は4つのワードを増加します.実はクラスのメンバー関数は実際には普通のグローバル関数と同じです.ただし、コンパイラはコンパイル時にメンバー関数にパラメータを追加し、このオブジェクトのポインタを渡します.メンバー関数アドレスはグローバルに既知であり、オブジェクトのメモリ領域にメンバー関数アドレスを保存する必要はありません.メンバー関数(非虚関数)の呼び出しは、コンパイル時に決定されます.myobjectのようにFun()のような呼び出しは、次のようにコンパイルされます.CObject_Fun(&myObject)の様子.関数はsizeofには含まれません.関数はコードなので、各オブジェクトに共用され、データ処理方式とは異なります.オブジェクトに関数ポインタがある必要はありません.オブジェクトはその各関数のアドレスを知る必要がないため(関数を呼び出すのは他のコードであって、そのオブジェクトではありません).クラスの属性はクラスのデータメンバーを指し、1つのオブジェクトをインスタンス化するとデータメンバーにメモリが割り当てられ、各オブジェクトのデータメンバーは対立し、メンバー関数は共通~静的メンバー関数と一般メンバー関数の唯一の違いはthisポインタがないため、非静的データ・メンバー.要するに,プログラム内のすべての関数はコード領域に位置する.3)静的メンバーはオブジェクトに属しておらず,sizeofはオブジェクトサイズをとる.上のことがわかったら、直してみてもいいです.class CObject{public:static int a;CObject();~CObject();void Fun();private:double m_count;//ここでdouble int m_indexに変更しました. };このクラスでsizeof()で測定したサイズは2*sizeof(double)=16 class CObject{public:static int a;CObject();~CObject();void Fun();private:char m_count;//ここでchar int m_indexに変更しました. };サイズは2*sizeof(int)=8 class CObject{public:static int a;CObject();~CObject();void Fun();private:double m_count;//ここでdouble int m_index;char c; };sizeof(char)+sizeof(int)
class Base
public:
~Base();
};
class Base { public: Base(); ~Base(); };
ここでは構造と解析が宣言されていることに気づいたがsizeof(Base)の結果は1.
空のクラスもインスタンス化されるため、クラスのインスタンス化とはメモリにアドレスを割り当て、各インスタンスにはメモリにユニークなアドレスが割り当てられます.同じように空クラスもインスタンス化されるので、コンパイラは空クラスに隠しバイトを追加し、空クラスがインスタンス化されるとユニークなアドレスが得られます.したがって、空のクラスのsizeofは1です.
構造関数は、構造関数などのメンバー関数とはsizeofとは関係なく、私たちのsizeofはインスタンスに対して、普通のメンバー関数は、クラス体に対して、1つのクラスのメンバー関数で、複数のインスタンスも同じ関数ポインタを共有しているので、自然にインスタンスの大きさに帰すことはできません.これは私の別のブログで述べています.
次のコードを見てください
class Base
public:
virtual ~Base();//各インスタンスに虚関数テーブルがある
{
}
int a;//4バイト
class Derive:public Base
public:
~Derive(){};
static int st;//非インスタンス排他
};
int main()
cout<
return 0;
結果は自然に
12
20
ベースクラスのint a;char *p;8バイトを占めます.
虚析構造関数virtual~Base()のポインタは4サブバイトです.
他のメンバー関数はsizeof統計に含まれません.
Deriveクラスは、まずBaseクラスの部分、つまり12バイトを持つ必要があります.
int d;char *p;8バイトを占める
static int st;sizeof統計に戻さない
だから全部で20バイトです.
Deriveにメンバーchar cを追加することを考えています.
class Derive:public Base
public:
~Derive(){};
static int st;
char *p;
この時、結果は
12
24
1つのchar c;4バイト増加し、クラスのサイズもclassバイトの整列のような補完ルールを遵守していることを示します.
具体的には私の「5分でバイトの位置合わせができます」を見ることができます.
ここで、以下の原則をまとめることができます.
1.クラスのサイズは、クラスの非静的メンバーデータのタイプサイズの和であり、つまり静的メンバーデータは考慮されない.
2.一般メンバー関数はsizeofとは無関係です.
3.ダミー関数は、ダミー関数テーブルに維持されるため、ポインタサイズ、すなわち4バイトを占有します.
4.クラスの合計サイズもclassバイトのように整列し、ルールを調整します.