By John Lakos
All essential behavior of our software must be documented, and yet there are important advantages, with respect to development, verification and testing, performance, and stability, for leaving the behavior for some combinations of inputs and initial conditions undefined. What is and is not defined behavior should therefore be readily discernible from the contract, especially when creating contracts that must span classes related by inheritance.
In Part 1 of this talk, we review components, interfaces and contracts in general, and the significance of narrow versus wide contracts in particular. In Part 2, we explore three kinds of inheritance: (1) Interface Inheritance resulting from pure-virtual functions; (2) Structural Inheritance resulting from non-virtual functions; and (3) Implementation Inheritance resulting from non-pure virtual functions. Proper contracts involving each of these distinct forms have different criteria that must be addressed. The three kinds of inheritance are compared, and their relative utility is explained. What’s more, several common uses of inheritance that are probably improper are summarily debunked.