const
const 修飾子
変数宣言に const 修飾子をつけることによって,その変数を定数として宣言することができます。
const 修飾された型の変数は,代入による値の変更が禁止されます。
定数として使用する変数に const 修飾子をつけておくことで,意図せぬ値の代入をコンパイル時に検出することができます。
const int n = 123;
n = 456; // 不可
C++ では,const 修飾された変数は定数として扱われるため,配列の要素数指定にも使えます。
const size_t size = 32;
double arr[size];
ちなみに,定数を定義するための方法には,C でよく使われるマクロ定数を使う方法もあります。
しかし,マクロ定数は const 定数と異なりコンパイラの型チェックの恩恵を受けることができないほか,マクロ定数の定義に記述した式がそのままマクロ定数の使用箇所に展開されて思わぬバグを生むことがあるため,できるだけ const 定数を使用するほうがよいでしょう。
#define SIZE 32
const ポインタ
ポインタ型については,const 修飾子を置く位置によって意味合いが異なります。
const 修飾子を * よりも前に書いた場合は,ポインタが指すデータのデータ型 (すなわち,* より前に書いたデータ型) に対して const が掛かります。
例えば,const int* は const int へのポインタを表し,ポインタ自体は再代入が可能です。
const 修飾子を * よりも後に書いた場合は,ポインタ型に対して const が掛かります。
例えば,int* const は int への const ポインタを表し,ポインタ自体が定数となります。
const int* p = &n; // const int へのポインタ
*p = 456; // 不可
p = NULL; // 可
int* const q = &m; // int への const ポインタ
*q = 456; // 可
q = NULL; // 不可
const 参照
参照先の変数の値の書き換えを防ぐ目的で,参照に対して const 修飾子をつけることもできます。
参照を const 化することで,参照先の変数の意図せぬ変更をコンパイル時に検出できます。
int a = 123;
const int& r = a; // const 参照は非 const 値を参照可能
r = 456; // 書き換え不可
const メンバ変数
インスタンスメンバ変数を const 化した場合,その初期化はコンストラクタの初期化子リストで行います。
class Class1
{
public:
const int n;
Class1() : n(1) { }
};
const 静的メンバ変数は,メンバ変数の宣言に直接初期化子を与えることもできます。
ただし,いずれにせよクラス定義の外に変数の定義は必要です。
class Class1
{
public:
static const int m = 1;
static const int n;
};
const int Class1::m;
const int Class1::n = 2;
ちなみに,整数型の static const メンバ変数は,enum を使って宣言することもできます。
class Class1
{
public:
enum { m = 1, n = 2 }; // enum ハック
};
int main()
{
std::cout << Class1::m << std::endl; // 出力: 1
}
const メンバ関数
メンバ関数の引数リストの後に const を付けると,その関数はメンバ変数の値を変更できません。
class Class1
{
public:
int n;
void func1() const; // const メンバ関数
};
void Class1::func1() const
{
n = 123; // 不可 (メンバ変数の値を変更してはならない)
}
mutable メンバ変数
const メンバ関数は,原則としてメンバ変数の値を変更できないが,mutable メンバ変数の値は変更できます。
class Class1
{
public:
mutable int n; // mutable メンバ変数
void func1() const;
};
void Class1::func1() const
{
n = 123; // 可
}