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.
This also isolates new bugs to the new code. By inheriting from an existing,
functional class and adding data members and methods (and redefining existing
methods), you leave the existing code – that someone else might still be
using – untouched and unbugged. If a bug happens, you know that
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 methods in order to reuse the code. At most, you just
import a package. (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 can be 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 that come from the problem
space.