C++空のクラスインスタンスサイズが0でない理由


初心者は対象向けのプログラミング言語を学ぶ時、多かれ少なかれ疑問に思っています.私たちが書いたコードは最終生がコンパイルしたコードとは大きく異なり、コンパイラがバックグラウンドでどんな仕事をしたのか分かりません.これらは私たちが言語層にとどまっているからです.言語層とは基本的な文法法則を教えてくれます.なぜこんなことをしたのか教えてくれませんか?今日皆さんと話した少しの悟りは私がプログラミングを学ぶ過程での経験であり、コンパイラの具体的な機能である.
まず、クラスのインスタンス化とは何かを知ります.クラスのインスタンス化とは、メモリにアドレスを割り当てることです.まず、例を見てみましょう.
#include<iostream>
using namespace std;
 
class a{};
class b{};
class c:public a
{
       virtualvoid fun()=0;
};
class d:public b,public c{};
 
int main()
{
       cout<<"sizeof(a)"<<sizeof(a)<<endl;
       cout<<"sizeof(b)"<<sizeof(b)<<endl;
       cout<<"sizeof(c)"<<sizeof(c)<<endl;
       cout<<"sizeof(d)"<<sizeof(d)<<endl;
       return  0;
}

プログラム実行の出力結果は次のとおりです.
sizeof(a)=1
sizeof(b)=1
sizeof(c)=4
sizeof(d)=8
なぜこのような結果になったのでしょうか.初心者はきっと悩むでしょう?クラスa,bは空のクラスであるのに,その大きさは0であるべきであるのに,なぜコンパイラが出力した結果は1であるのか.これが私たちがさっき言ったインスタンス化の原因(空のクラスは同様にインスタンス化することができる)で、各インスタンスはメモリの中で1つのユニークなアドレスを持っていて、この目的を達成するために、コンパイラは往々にして1つの空のクラスに隠れている1バイトを加えて、このように空のクラスはインスタンス化した後にメモリの中でユニークなアドレスを得ました.だからa,bの大きさは1です.
クラスcはクラスaから派生するもので、その中に純粋な虚関数があり、虚関数があるため、虚関数を指すポインタ(vptr)があり、32ビットのシステムでポインタに割り当てられるサイズは4バイトであるため、最後にcクラスのサイズは4となる.
類dの大きさは更に初心者を疑わせるでしょう、類dは類b、cから派生して最近来たので、その大きさは両者の和5であるべきで、どうして8ですか?これは、メモリにおけるインスタンスのアクセス効率を向上するためである.クラスのサイズはシステムの整数倍に調整されることが多い.どの最近の倍数がそのクラスのサイズであるかという近傍の法則をとるため、クラスdのサイズは8バイトである.
もちろん、異なるコンパイラで得られる結果は異なるかもしれませんが、この実験は初心者に、クラスが空であるかどうかにかかわらず、インスタンス化することができ(空のクラスもインスタンス化することができます)、各インスタンスにはユニークなアドレスがあることを教えてくれます.私が使っているコンパイラはvc++6.0です.
次の例を見てみましょう.
class a{
private:
       intdata;
};
class b{
private:
       intdata;
       staticint data1;
};
int b::data1=0;
int mian()
{
       cout<<"sizeof(a)="<<sizeof(a)<<endl;
       cout<<"sizeof(b)="<<sizeof(b)<<endl;
       return0;
}

実行結果:
sizeof(a)=4;
sizeof(b)=4;
なぜクラスbにデータメンバーが1つ増えたのに、クラスaのサイズと同じサイズになったのでしょうか.なぜなら、クラスbの静的データメンバーはコンパイラによってプログラムのglobal data membersに配置され、クラスのデータメンバーである.しかし、クラスのサイズには影響しない.このクラスが実際にどれだけのインスタンスを生成したか、どれだけの新しいクラスを派生したかにかかわらず、静的メンバーデータはクラスに永遠に1つのエンティティしか存在しないからである.クラスの非静的データメンバーはインスタンス化された場合にのみ存在するが、クラスの静的データメンバーが宣言されると、クラスがインスタンス化されるかどうかにかかわらず、すでに存在する.このように、クラスの静的データメンバーは特殊なグローバル変数であるため、a,bのサイズは同じである.
次に、コンストラクション関数とコンストラクション関数のあるクラスの大きさを見てみましょう.それはどのくらいですか.
class A{
public :
       A(inta)
       {
              a=x;
       }
       voidf(int x)
       {
              cout<<x<<endl;
       }
       ~A(){}
private:
       intx;
       intg;
};
 
class B{
public:
private:
       int  data;
       intdata2;
       staticint xs;
};
int B::xs=0;
 
int main()
{
       cout<<"sizeof(A)"<<sizeof(A)<<endl;
       cout<<"sizeof(B)"<<sizeof(B)<<endl;
       return0;
}

プログラム実行出力結果:
sizeof(a) 8
sizeof(b) 8
それらの結果はすべて同じで、クラスの大きさはその中の構造関数、構造関数、その他のメンバー関数とは関係なく、その中のメンバーデータだけに関係していることがわかる.
以上の例からクラスのサイズを発見するのは難しくありません.
1.クラスの非静的メンバーデータのタイプサイズの和である.
2.言語のいくつかの特性(例えば、虚関数を指すポインタ)をサポートするために、コンパイラに追加されたメンバー変数のサイズがある.
3.アクセス効率を最適化するために行うエッジ調整.
4クラスの構造関数、構造関数、その他のメンバー関数とは関係ない.
変換元:http://blog.csdn.net/hitblue/article/details/3726754