const 宣言できたとしても、すべきでない場合

例として次のような int をラップしているだけの Number クラスを考える。

class Number {
  int *const v;
public:
  Number() : v(new int(0)) {}
  ~Number() { delete v; }
  void set(int value) const { *v = value; }
  int get() const { return *v; }
};

ここで set 関数は Number の抱えるポインター v の値を変更しないので const 宣言できる。
そしてこれは警告なしにコンパイル可能である。 C++ の文法に照らしてみるかぎり間違いはない。

しかし考えてみてほしい。 set は本当に const な関数だろうか?

メンバー関数が const と宣言されている場合、その const オブジェクトに対する呼び出しが可能ということだ。

const Number v;
printf("%d\n", v.get()); // you got 0
v.set(1);
printf("%d\n", v.get()); // you got 1

前掲のコード片をみるとわかるように、不変であるはずの Number オブジェクトに対して set() を呼び出すことができ、悪いことに、そのふるまい (ここでは get() による値の参照結果) が変わってしまっている。

関数引数には、メンバー変数には、局所変数には、積極的にできるかぎり const をつけよう。

しかし、クラスの設計時には立ち止まってよく考えてほしい。 そのメンバー関数は、オブジェクトの振る舞いを変えないだろうか? 振る舞いを変えてしまうなら、そのメンバー関数には const をつけてはいけない。 たとえコンパイラーが文句を言わないとしても。

クラスのメンバー変数にポインターがいるときには、とくに注意してほしい。 ポインターの先にいるオブジェクトを「知っている」だけなのか、そのオブジェクトを所有していて「使っている」かで答えは変わる。