liveBook · Manning

Programming by contract

As explained in Object-Oriented Software Design in C++

Programming by contract is a software design technique that specifies preconditions, postconditions, and invariants for program components and may check them during execution.

Programming by contract makes a class’s expected behavior explicit through preconditions, postconditions, and a class invariant. These promises reduce surprises for callers and help keep objects valid at run time. section 6.0 section 6.3

A contract divides responsibility between the caller and the function:

  • Precondition: a Boolean condition that must be true before a call. The caller must check it; the function is not required to behave suitably when it is false. section 6.3.2
  • Postcondition: a Boolean condition that must be true when a function returns after its precondition was satisfied. The function is responsible for meeting it. section 6.3.3
  • Class invariant: a condition that remains true before and after every member-function call, except temporarily during mutation, so objects are not left invalid. section 6.3

CircularBuffer contract

A CircularBuffer stores integers in a fixed-capacity dynamic array. Its add() precondition is that the buffer is not full, while remove() requires that it is not empty. The tester checks get_count() before normal calls, but calls remove() once after the buffer is empty; the assertion fails because count > 0 is false. The implementation also checks postconditions after add() and remove(), and class_invariant() verifies that head and tail remain within the capacity range. section 6.3.1

C++ has no native programming-by-contract support in the described treatment, so assertions, comments, and helper functions implement the checks. Runtime checks can aid debugging, but contracts need not be placed on every class; critical classes are the suggested focus. section 6.3

Inheritance requires compatible contracts. An overriding function must accept at least the inputs accepted by the superclass and promise results no weaker than the superclass promise. Otherwise, code using the superclass interface can fail for a valid subclass object. section 7.0 section 7.5

How Object-Oriented Software Design in C++ covers it

How deep it goes
Explains responsibilities, runtime assertions, a CircularBuffer implementation, and inheritance constraints, but does not provide native C++ contract syntax.
Examples
Demonstrates contracts with CircularBuffer operations and Shipment, Expedited, and International subclasses.
What it assumes
Assumes basic classes, member functions, and inheritance while teaching contract terminology and caller-versus-function responsibilities explicitly.
What you can do after
Apply it by documenting and asserting class contracts, checking caller obligations, and evaluating subclass overrides for compatibility.
How it connects
Connects preconditions, postconditions, class invariants, assertions, inheritance, and the Liskov Substitution Principle.

Also explained in

Compare how 3 books explain programming by contract →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Object-Oriented Software Design in C++. The section links point to the parts of the book it draws on.