const修飾子

2016年06月07日 (火) 15時27分46秒
このエントリーをはてなブックマークに追加

const修飾子について

const修飾子はさまざまな場面で使うことができる
第一に変数につける場合である

const int num = 100;
num = 300;		//error

変数の型の前にconstを付けることでその変数が変更できないようにできる
後から値が入れられないので初期化が必須である
また、クラスのメンバ変数にもconstをつけることができる
この場合初期化は次のように行う

class Test{
	const int num;
public:
	Test():num(100){}
};

さて、次のプログラムはエラーが出るだろうか?

int num = 100,num2 = 200;
const int *pnum = #
pnum = &num2;

実はこれはエラーとならない
ただし次のプログラムはエラーとなる

int num = 100;
const int *pnum = #
*pnum = 200;// error

つまり、ポインタの中身の変更ができなくなっているのである
次のようにするとポインタ自体が変更できなくなる。ただし中身の変更は可能

int num = 100,num2 = 200;
int * const pnum = #
pnum = &num2;// error
*pnum = 200;// OK

どちらも変更できないようにしたければ次のようにする

int num = 100,num2 = 200;
const int * const pnum = #
pnum = &num2;// error
*pnum = 200;// error

ちなみに、次はどちらも同じであることに注意

const int * pnum;
int const * pnum;

ポインタ自体の変更を禁止したければ*の後に書かないといけない

上記のことは関数の仮引数でも行える
特にconstを付けた参照は値の変更はしたくないがコピーをするには大きいクラスなどを渡すときに便利である

class MyClass{
public:
	int x;
};

int func(const MyClass &data){
//	data.x = 100;// error
	return data.x+100;
}

ただし次の場合はエラーとなる

class MyClass{
public:
	int x;
	int get_x(){return x;}
};

int func(const MyClass &data){
	return data.get_x()+100;// error
}

これはget_xが中身を変更するかどうかが分からないのでエラーなのである

constはメンバ関数にもつけることができる
メンバ変数を変更しないと宣言するわけである

class MyClass{
public:
	int x;
	int get_x() const {
//		x=10;// error
		return x;
	}
};

こうするとget_x関数がメンバ変数を変更しないと分かるので、先の例の関数でエラーが出なくなる
constがついたオブジェクトはconst付きのメンバ関数しか呼び出せないのである
参照について説明したがポインタでも同様。参照でもポインタでもないconstなオブジェクトも一緒
ちなみにconstつきのメンバ関数と付いてないメンバ関数は別扱いなので次のようなこともできる

class MyClass{
public:
	int x;
	int get_x(){return x+=1;}
	int get_x() const {return x+1;}
};

関数がオーバーロードされているのである
constつきのオブジェクトではconstつきのメンバ関数が、constのないオブジェクトではconstのないメンバ関数が呼ばれる。(通常その動作を変えることはないと思うが)

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