class A {public: A() { n = 0; } int value() { return next(n); } void strange() { next(-3); } protected: virtual int next( int i ) { return n = n + i * i; } int n; };
invariant A:
class B : public A {public: B() : A() { } protected: virtual int next( int i ) { return n = n + (n + 1) * i; } };
not invariant A
A* a = new A; a->value(); a->strange(); a->value();ok
A* b = new B; b->value(); b->strange(); b->value();error
int f(A* a) { a->strange(); return a->value(); }
As an aside, it should be noted that the problems illustrated above would not have occurred so easily if the invariant and the behavior of the base and derived classes had been made explicit by means of a client-server contract. Moreover, annotating the methods with the proper pre- and post-conditions would allow automatic monitoring of the runtime consistency of the objects.