C++ constメンバ関数とmutable

クラス型オブジェクトのインスタンスを作る時に
constキーワードをつけると、それ以降、
そのインスタンスのメンバ変数の値が変更できなくなり、定数化します。

そして、なぜかそのインスタンスのメンバ関数も使用不可になってしまいます。

「メンバ変数を変更しないメンバ関数」ならば呼べていいのでは?

と思うのですが、C++では、どのメンバ関数がメンバ変数の値を変更するか
判断できない。と言う事になってるらしいので、
安全のため、全てのメンバ関数を呼べなくなっています。

動作例

#include <iostream>

using namespace std;

class hito {
public:
int age;

hito(int data) {age = data; }
void show();

};

void hito::show() {
      cout << "ageの値は" << age << "です。" << '\n';
}

void main(void) {
      const hito satou(10);
      satou.show();      // コンパイルエラー
}

この例では、クラスhitoのインスタンスsatouがconst付きで作成されています。

そして、インスタンスsatouを使ってメンバ関数showを呼ぼうとすると、
コンパイルエラーとなります。


このような仕様になっていては不便なので、
const付きのインスタンスが作られ、そのメンバ関数を呼びたい時には、
そのメンバ関数内でメンバ変数が変更しない事を条件に、
抜け道が用意されています。

呼び出したいメンバ関数の定義時と実体を記述する際に、
キーワードconstを付けます。
そうすると、const付きのインスタンスからでも
const付きのメンバ関数だけは呼び出せるようになります。

このconst付きのメンバ関数をconstメンバ関数と呼びます。

動作例

#include <iostream>

using namespace std;

class hito {
public:
int age;

hito(int data) {age = data; }
void show() const;            // const付きで定義

};

void hito::show() const {      // const付きで記述
      cout << "ageの値は" << age << "です。" << '\n';
}

void main(void) {
      const hito satou(10);
      satou.show();            // 通常通り呼べる
}

この例では、クラスhitoのメンバ関数showにキーワードconstをつけて、
constメンバ関数をつくった例です。

こうすれば、const付きのインスタンスからconstメンバ関数だけは
呼び出せます。


さらに高度な処理をしたいと言う場合、
constキーワードだけでは解決できない事があります。

例えば、const付きでインスタンスを作成したけど、
一部のメンバ変数だけは、特別に変更を許可したい。
と言った場合です。

こう言う要求に対応する機能がmutableキーワードです。

このmutableキーワード付きで定義されたメンバ変数は、
const付きでインスタンスを作成した場合も、特別に変更できるようになります。

動作例

#include <iostream>

using namespace std;

class hito {
public:
int age;
mutable int sinchou;

hito(int data1, int data2) { age = data1; sinchou = data2; }
void set_sinchou(int data) const { sinchou = data; }

};

void main(void) {
      const hito satou(10, 170);
      satou.age = 20;            // コンパイルエラー
      satou.sinchou = 180;       // メンバ変数に直接アクセス
      satou.set_sinchou(200);    // constメンバ関数からアクセス
}

この例では、クラスhitoのメンバ変数sinchouが
mutableキーワードで定義されています。

始めに、const付きのインスタンスsatouが作成されます。

通常のメンバ変数ageは値を変更できませんが、
mutableメンバ変数sinchouは、値を変更する事ができます。

また、constメンバ関数set_sinchouの中からでも
mutableメンバ変数sinchouの値を変更する事ができます。