クラス内不変表明
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文字列。
PascalはC言語とはちょっと違った方法で文字列を表現してた。
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)); } }
となる。