真のDbC
2006/04/18
先日までのエントリで、C++
によるシンプルなDbC
を理解することができたと思います。しかし、本当のDbC
にはもっと強力な特徴があります。再現にあたり注意を払うべきDbC
の特徴は以下です。
-
クラス不変条件は継承されます。派生クラスの不変条件は基底クラスの不変条件を暗黙的に呼び出します。
-
クラス階層のメンバ関数において、派生クラスのメンバ関数の事前条件は、すべてのオーバーライド関数の事前条件とORされます。事後条件はANDされます。
(日本語訳においてこちらのページを参考・引用)
言い換えれば、DbC
はクラス会層に対して特別な動作を行います。クラス不変条件の継承を実現するために、基底クラスの不変条件を呼び出すように派生クラスを記述しなければなりません。例のページには次のようなコードが示されています:
void
A::foo()
{
check_invariant(*this);
...
check_invariant(*this);
}
// B.h:
#include "A.h"
class
B
:
public
A {
public:
#ifdef DBG
virtual
void invariant()
{ ...contracts...
A::invariant();
}
#endif
void
bar();
};
事前条件と事後に関して、メンバ関数内部で基底クラスの該当条件チェックを呼ぶコードを記述すべきです。
しかし、深いクラスでは、すべての条件を呼ばなければならないため、それは非常に複雑になるでしょう。
class
B
:
A
{
protected:
#if DBC
int
foo_preconditions() {
...Bpreconditions...
}
void
foo_postconditions() {
...Bpostconditions...
}
#else
int
foo_preconditions() {
return 1;
}
void
foo_postconditions() { }
#endif
void
foo_internal()
{
...implementation...
}
public:
virtual
void foo()
{
assert(foo_preconditions()
|| A::foo_preconditions());
foo_internal();
A::foo_postconditions();
foo_postconditions();
}
};
C++
で事後条件を仕様(理想?)通りに実現することができるでしょうか? 恐らくそれは難しいでしょう。特に深い事前条件と事後条件はコードが複雑過ぎるため、使用に耐えないと思われます。しかし、実用(実益)レベルにおいて、これらのすべての仕様を実現させる必要があるかというとそうではなく、よく必要とする仕様だけを扱っても恩恵に預かれるはずです。本気で取り組むのであれば、プリプロセッサの開発が有効であると考えられます。