Basically programming by contract creates a contract between the software developer and software user - in Meyer's terms the supplier and the consumer. Every feature, or method, starts with a precondition that must be satisfied by the consumer of the routine. And each feature ends with postconditions which the supplier guarantees to be true (if and only if the preconditions were met). Also, each class has an invariant which must be satisfied after any changes to the object represented by the class. In the other words, the invariant guarantees the object is in a valid state.
As an example, you might have a routine which expects an incoming paramater to be a non-NULL class pointer and guarantees to return the class with some new data stuffed in it. A C++ routine might look like:
SomeClass::someFunction ( AnotherClass *fillMeWithData ) { // check any preconditions here preCondition ( fillMeWithData ); // non-NULL check // do your stuff to add the functionality here ... // check post conditions postCondition ( fillMeWithData->hasData() ); -- did we do what we said postCondition ( checkInvariant() ); -- class invariant check required -- because of lack of lang support }
The class invariant would check that the class is in a valid state after the call to someFunction. Note that in C or C++, a very simple definition of pre and post condition constructs is simply:
#define preCondition(c) assert(c) #define postCondition(c) assert(c)
A better definition would allow compile time options to turn these conditions on or off individually (you might turn them off for performance before shipping a release, for instance). Better yet might be to have assert() used as a default but allow the developer to override assert() with an exception handling mechanism as well having the compile time options.
However, there is still a giant limitation in each of these implementations: they do not follow through inheritance. That is, if I create a new class derived from SomeClass above and someFunction was a virtual function which I am now redefining, I lose my contractual agreement for the new method. I must remember to manually insert the same pre/postconditions in this new method plus any alternative conditions for this particular method. Most likely this means you must have access to the C++ class implementation source code. And proper class invariant support is even trickier than pre/postconditions. BTW, if anyone has nice implementations for pre/postconditions and invariants in C++ that they'd like to share, I'd like to check them out as I have struggled unsuccessfully to find a solution that I am happy with. (On the other hand all of this technology is built into the Eiffel language.)
Still I think adding assertion technology (pre and post conditions) to C++ implementations is generally a good thing. Still not sold? Give it a try it on your next project and see if it helps.