Boost logo

Boost :

From: Michael D. Crawford (crawford_at_[hidden])
Date: 2001-03-14 23:03:13


Does anyone have any thoughts or working code for validating class invariants
and enforcing programming by contract in C++?

I'm particularly interested in how this might be handled in the face of:

- templates
- polymorphism

In a recent project I found the following simple code invaluable: I created
member functions named "MembersValid()" that were included only in debug builds:

class Example{
        public:
                void AMemberFunction();
#ifndef NDEBUG
                bool MembersValid();
#endif
        private:
                // ... some data members whose validity get checked here
};

Then I'd test MembersValid() at the entry point of all my member functions:

void Example::AMemberFunction()
{
        assert( MembersValid() );
}

because assert itself is a macro controlled by NDEBUG, in release builds the
test, the implementations of MembersValid (which were also guarded by #ifndef
NDEBUG) and the interface of it would all disappear.

Being a public function, a user can always validate one of these things:

   Example *myEx = new Example;

   assert( myEx->MembersValid() );

My thinking is that the invariant must always hold true "outside" any public
or protected member function, and should hold true for private functions, but
not necessarily - if two private member functions are used in a two step
process that breaks and restores the invariant, I would think this is
permissible, although potentially troublesome.

Among the things I'd check in MembersValid():

#ifndef NDEBUG
bool Example::MembersValid()
{
        if ( this == NULL )
                return false;
        //... etc
        return true;
}
#endif

Here's the class invariant header file for the Whisper cross-platform framework:

http://magnes.augsburg.edu/Whisper/html/xinvariant_h-source.html

While it could be very helpful to use programming by contract in a template,
it would be troublesome to require any class its instantiated with to provide
validation functions - but it would also be very helpful to do so. What do I do?

And what about polymorphism? The whole point of programming by contract is
that the derived classes must have the same contract as the base classes, but
they may impose additional constraints on the invariant - the base class
invariant must hold true, but they may have invariants of their own. But
polymorphic methods cannot impose additional constraints and must ensure the
same things in derived classes;
newly-defined functions in a derived class that don't override a base member
could feel free to have its own constraints though.

Mike

-- 
Michael D. Crawford
GoingWare Inc. - Expert Software Development and Consulting
http://www.goingware.com/
crawford_at_[hidden]
   Tilting at Windmills for a Better Tomorrow.

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk