クラス内不変表明

friend:dmpが"クラス内不変表明が分け分からん"と言っていたので、適当に実例を上げておこう。

日付クラス

まずは、日付(Date)クラスを考えてみる。
日付っていうのは、年(year)、月(month)、日(day)で定義されるから、こんなクラスになる。

class Date{
 int year,month,day;
public:
 // ...
}

しかしながら、13月とか32日とかは存在しないから、monthとdayには暗黙の制限が課せられている。
じゃあ、その暗黙の制限を不変表明を使って表明してやる。

class Date{
  int year,month,day;
public:
  // ...
  
  // 不変表明
  invariant{
    assert(1 <= month && month <= 12);
    assert(1 <= day && day <= 31);
  }
}

ほいで、すべてのメンバ関数と呼び出し前と呼び出し後に、この不変条件がチェックされる。
そうすることで、常に(プログラムが動いている限り)、Dateのmonthとdayは常に正しい値であることが保証できる。
ちなみに実は、このコードはC++じゃなくて、D言語D言語だと、言語レベルで契約が組み込まれているので、説明にうってつけだった。まあ、わかるでしょう。
あと、厳密にはyearとmonthによってdayの制限はもっと強くなるんだけど、まあ勘弁して。

Pascal文字列

もう一つの例はPascal文字列。
PascalC言語とはちょっと違った方法で文字列を表現してた。
C言語は文字列はnullが現れるまでと決められていたけれど、Pascalは0バイト目に文字列の長さを格納して、1バイト目から文字を格納してた。Pascal文字列だと、255文字しか扱えない代わりに、null終端文字列に比べて高速に文字の長さを取得できる。
で、これに由来して、長さを別のところに保存している文字列をPascal文字列とと呼ぶことがある。あ、friend:dmpは「憂鬱なプログラマのためのオブジェクト指向入門」を読んだから知ってるか。
こいつをクラスで表現してやると、こうなる。

class String{
  int length;
  char* string;
public:
  // ......
}

で当然、lengthはstringの長さでなければならない。
だから、不変表明は

class String{
  int length;
  char* string;
public:
  invariant{
    assert(length == strlen(string));
  }
}

となる。