const修飾子 の変更点

このエントリーをはてなブックマークに追加

const修飾子について

const修飾子はさまざまな場面で使うことができる
第一に変数につける場合である
#code(cpp){{
const int num = 100;
num = 300;		//エラーとなる
num = 300;		//error
}}
変数の型の前にconstを付けることでその変数が変更できないようにできる
後から値が入れられないので初期化が必須である
また、クラスのメンバ変数にもconstをつけることができる
この場合初期化は次のように行う
#code(cpp){{
class Test{
	const int num; // ここで=100;等として初期化をしようとするとエラーとなる
	const int num;
public:
	Test():num(100){}
};
}}
さて、次のプログラムはエラーが出るだろうか?
#code(cpp){{
int num = 100,num2 = 200;
const int *pnum = #
pnum = &num2;
}}
実はこれはエラーとならない
ただし次のプログラムはエラーとなる
#code(cpp){{
int num = 100;
const int *pnum = #
*pnum = 200;// エラー
*pnum = 200;// error
}}
つまり、ポインタの中身の変更ができなくなっているのである
次のようにするとポインタ自体が変更できなくなる。ただし中身の変更は可能
#code(cpp){{
int num = 100,num2 = 200;
int * const pnum = #
pnum = &num2;// エラー
*pnum = 200;// これはOK
pnum = &num2;// error
*pnum = 200;// OK
}}
どちらも変更できないようにしたければ次のようにする
#code(cpp){{
int num = 100,num2 = 200;
const int * const pnum = #
pnum = &num2;// エラー
*pnum = 200;// これもエラー
pnum = &num2;// error
*pnum = 200;// error
}}
ちなみに、次はどちらも同じであることに注意
#code(cpp){{
const int * pnum;
int const * pnum;
}}
ポインタ自体の変更を禁止したければ*の後に書かないといけない

上記のことは関数の仮引数でも行える
特にconstを付けた参照は値の変更はしたくないがコピーをするには大きいクラスなどを渡すときに便利である
#code(cpp){{
class MyClass{
public:
	int x;
};

int func(const MyClass &data){
//	data.x = 100;// エラー
//	data.x = 100;// error
	return data.x+100;
}
}}
ただし次の場合はエラーとなる
#code(cpp){{
class MyClass{
public:
	int x;
	int get_x(){return x;}
};

int func(const MyClass &data){
	return data.get_x()+100;// エラー
	return data.get_x()+100;// error
}
}}
これはget_xが中身を変更するかどうかが分からないのでエラーなのである

constはメンバ関数にもつけることができる
メンバ変数を変更しないと宣言するわけである
#code(cpp){{
class MyClass{
public:
	int x;
	int get_x() const {
//		x=10;// エラー
//		x=10;// error
		return x;
	}
};
}}
こうするとget_x関数がメンバ変数を変更しないと分かるので、先の例の関数でエラーが出なくなる
constがついたオブジェクトはconst付きのメンバ関数しか呼び出せないのである
参照について説明したがポインタでも同様。参照でもポインタでもないconstなオブジェクトも一緒
ちなみにconstつきのメンバ関数と付いてないメンバ関数は別扱いなので次のようなこともできる
#code(cpp){{
class MyClass{
public:
	int x;
	int get_x(){return x+=1;}
	int get_x() const {return x+1;}
};
}}
関数がオーバーロードされているのである
constつきのオブジェクトではconstつきのメンバ関数が、constのないオブジェクトではconstのないメンバ関数が呼ばれる。(通常その動作を変えることはないと思うが)

const修飾子をつけることでその変数や関数がどのように扱われるかを明示することができるし、変更ができなくなるので間違いが起き難くすることができる
また、プログラマの意思を明確にコンパイラに伝えることができるので、コンパイラによる最適化がより適切に行われるようになるメリットもある。