C++const詳細

4624 ワード

このブログを見て、c++のconstについてもっと深く理解できると信じています.
constの最初の動機は、#defineに代わって値の代替を行うことである.これ以降、ポインタ、関数変数、戻りタイプ、クラスオブジェクト、メンバー関数に使用されました.
まず、define前処理コマンドdefineは、制限なくマクロを確立し、値の代わりに使用することができ、前処理期間にのみ存在する.プリプロセッサはいくつかのテキストの代替を行うだけで、タイプチェックの概念もタイプチェックの機能もありません.実際のプログラミングでは、プリプロセッサの盲目的な代替は予想外の問題を生み出します.次の文があります.
#define LENGTH 100
const int length=100;
char buf_L[LENGTH];
char buf_l[length];

LENGTHは名前で、前処理中に存在するだけで、コンパイラに見られたことがないかもしれませんが、コンパイラがソースコードの処理を開始する前にプリプロセッサに移動され、LENGTHという名前はシンボルテーブルに入っていないので、ストレージスペースを占有しません.コンパイル段階でコンパイラが見たのはchar buf_ですL[100]; では、defineが確立したマクロはconst定数に対してどのような欠点があるのでしょうか.
1、const定数は言語定数としてコンパイラに見られるに違いなく、シンボルテーブルに入りますが、#defineで定義されたマクロは表示されません.プリプロセッサは、すべてのマクロを対応するテキストに置き換えるため、コンパイル後のターゲットコードに複数の置換テキストが表示され、コード量が増加する可能性があります.
2、パラメータ付きマクロ定義はコードを難解にし、エッジ効果をもたらす可能性があります.各パラメータにカッコを付けるのに十分注意していても、予想外のことが起こる可能性があります.
次の2つの例を見てみましょう.
#define CALL_WITH_MAX(a,b) f((a)>(b)?(a):(b))
int a=5,b=0;
CALL_WITH_MAX(++a,b);//a     
CALL_WITH_MAX(++a,b+10);//a     

ここで、fを呼び出す前に、aのインクリメント回数は、それが誰と比較されるかに依存する.
主役:const
1、const変数
値を変更しないようにするにはconstにする必要があります.コンパイラはconstの値を変更できないことを保証します.
通常、C++コンパイラはconstのストレージスペースを作成しません.逆に、この定義をシンボルテーブルに保存します.externでconst変数を修飾しない限り、externは外部リンクを使用することを意味します.これによりconst変数にストレージスペースが割り当てられます.また、const変数にアドレスを取ると、コンパイラもconst変数にストレージスペースが割り当てられます.
次のコードを見てみましょう.
const int i=100;
const int j=i+10;
long address=(long)&j;
char buf[j+10];

const変数iはコンパイル中のconstであり、コンパイラはシンボルテーブルに保存し、ストレージスペースを割り当てない.const変数jはiから算出され,同様にコンパイル期間のconstであり,コンパイラによってシンボルテーブルに格納される.次の行はconst変数jに対してアドレス取得操作を行い、コンパイラにconst変数jに記憶空間を割り当てさせる.次の行はbuf配列を定義し、配列サイズはj+10です.コンパイラはjの値を予め知る必要があり、jの値は2つの場所に格納され、1つはシンボルテーブル、1つはメモリに格納されるが、コンパイラの間、コンパイラは実行時のメモリの値を知ることができないため、シンボルテーブルに保存されているjを持ってj+10の値を計算し、buf配列に空間を割り当てるしかない.
しかし、コンパイラがconst変数のコンパイル中の値を知らない場合はどうなりますか?
int main()
{
   cout<

const変数cの値はコンパイル中にはわかりません.コンパイラはストレージスペースを割り当てる必要があります.この場合、constは変更できない記憶空間を意味し、その初期化は定義点で行わなければならず、定義時に初期化しなければならず、初期化後、その値は変更できない.同様にconst変数c 2の値はcの値から計算され、コンパイル中もc 2の値が分からないため、コンパイラもc 2に記憶空間を割り当てる必要がある.
2、constに関するポインタ
まず覚えておいてください.キーワードconstが星の左側に現れた場合、被指物が定数であることを示します.アスタリスクの右側に表示される場合は、ポインタ自体が定数であることを示します.星の両側に現れると、被指物とポインタの両方が定数であることを示します.
1)constへのポインタ
const int* u;
int const* v;

2つのintタイプを指すポインタu,vはconstで修飾され、constはアスタリスクの左側に表示されます.これは、2つのポインタがconst intタイプを指すポインタであることを意味します.つまり、それらの指すものは定数であり、修正できません.ポインタ自体は定数ではなく、修正できます.
しかし、一般的には、プログラムをより読みやすくするために、第1の形式を堅持しなければならない.
2)constポインタ
int d=1;
int* const w=&d;

intタイプを指すポインタwは定義時にconstで修飾され、constは星の右側に現れ、これはwがconstポインタであることを意味し、すなわちwの指すものは定数ではなく、修正することができ、w自体は定数であり、修正できないことを意味する.したがってconstポインタw定義時にはintタイプ変数dを指す初期化が必要である.
3)constタイプへのconstポインタ
const int a=10;
const int* const b=&a;

intタイプを指すポインタbは、定義時にconst修飾を用い、constはアスタリスクの左側にもアスタリスクの右側にも現れる.これは、bがconstポインタであり、bの指すものもconstタイプであることを意味する.したがってconstポインタb定義時には、const intタイプ変数aを指す初期化が必要である.
覚えておいてください.constオブジェクト以外のアドレスをconstポインタに割り当てることができます.変更できるものを変更したくない場合があるからです.しかしながら、constオブジェクトのアドレスを非constポインタに割り当てることはできない.これは、割り当てられたポインタによってオブジェクトの値を変更する可能性があるからである.
3、constに関する関数パラメータと戻り値
1)const値の転送
関数パラメータが値で渡されている場合は、次のようなパラメータを指定できます.
void f1(const int i)
{
   i++;//   
}

関数ではconstにはパラメータを変更できないという意味があります.したがって、関数作成者にサービスされ、関数呼び出し者とは関係ありません.値によって伝達されるパラメータは元の変数のコピーにすぎないため、関数内のパラメータの変更は元の変数の値に影響しません.
2)const値を返す
組み込みタイプでは、値によって返されるconstかどうかは重要ではありませんので、値によって組み込みタイプを返す場合は、混同を起こさないようにconstを削除する必要があります.
値によって組み込みタイプが返されると、constが機能しないのは、コンパイラが変数ではなく常に値を左にしないためです.
4、constに関するクラス
1)クラス内のconst
1つのクラスに通常のconstを作成する場合は、初期値を与えることはできません.この定数では、各オブジェクトに異なる値を含めることができるからです.この初期化作業は構造関数で行わなければならない.例:
class Fred
{
   const int size;
public:
   Fred(int sz):size(sz){}
};

2)constオブジェクトとメンバー関数
メンバー関数がconstであることを宣言すると、コンパイラにメンバー関数がconstオブジェクトで呼び出されることを示すことになります.constとして明示的に宣言されていないメンバー関数は、オブジェクト内のデータメンバーを変更する関数とみなされ、コンパイラはconstオブジェクトとして呼び出すことを許可しません.
キーワードconstは、const関数の宣言と定義に同じ方法で繰り返し表示されなければなりません.そうしないと、コンパイラはそれらを2つの異なる関数と見なします.
class X
{
   int i;
public:
   X(int ii);
   int f() const;
   int d();
};

X::X(int ii):i(ii){}
int X::f() const 
{
   return i;
}
int X::d()
{
   i++;
}

int main()
{
   X x1(10);
   const X x2(20);
   x1.d();// const      const    
   x1.f();
   x2.d();//  !const       const    
   x2.f();
}

データ・メンバーを変更しない関数は、constオブジェクトとともに使用できるようにconstとして宣言する必要があります.