One
of the advantages of inheritance is that it supports
incremental
development
by allowing you to introduce new code without causing bugs in existing code and
isolating new bugs to the new code. By inheriting from an existing, functional
class and adding data members and member functions (and redefining existing
member functions) you leave the existing code – that someone else may
still be using – untouched and unbugged. If a bug happens, you know
it’s in your new code, which is much shorter and easier to read than if
you had modified the body of existing code.
It’s
rather amazing how cleanly the classes are separated. You don’t even need
the source code for the member functions to reuse the code, just the header
file describing the class and the object file or library file with the compiled
member functions. (This is true for both inheritance and composition.)
It’s
important to realize that program development is an incremental process, just
like human learning. You can do as much analysis as you want, but you still
won’t know all the answers when you set out on a project. You’ll
have much more success – and more immediate feedback – if you start
out to “grow” your project as an organic, evolutionary creature,
rather than constructing it all at once like a glass-box skyscraper.
Although
inheritance for experimentation is a useful technique, at some point after
things stabilize you need to take a new look at your class hierarchy with an
eye to collapsing it into a sensible structure. Remember that underneath it
all, inheritance is meant to express a relationship that says, “This new
class is a
type
of
that old class.” Your program should not be concerned with pushing bits
around, but instead with creating and manipulating objects of various types to
express a model in the terms given you by the problem’s space.