Concepts / Benefits of Class Hierarchies

Benefits of Class Hierarchies

Implementation inheritance means a base class provides functions or data that simplifies the implementation of derived classes.

  • Programming

Predicting Where Shared Work Lives

Suppose you are writing several related classes. Each one needs to draw a shape, set up its starting values, and store its position. If every class writes that same work from scratch, the program grows longer, and every copy has to be kept in step with the others. This article looks at one way out of that problem: a base class that holds the shared work, and derived classes that rely on it.

What do you think happens?

When a new Smiley is created, whose constructor is used to set it up: only Smiley's own, or a constructor that belongs to a different class?

  • Only Smiley's own constructor, with no help from another class

  • The constructor of its base class Circle, which Smiley reuses

Reveal answer
Answer:

The constructor of its base class Circle, which Smiley reuses

Smiley does not write its own version of the setup code. It uses Circle's constructor, so control passes into Circle when a Smiley is created.

What Implementation Inheritance Means

Definition

Implementation inheritance means a base class provides functions or data that simplifies the implementation of derived classes.

The key word in this definition is implementation. A base class in this sense is not only describing what a derived class is. It is also supplying working parts that the derived class can use when it is written. The benefit is that a derived class can be shorter and simpler, because the difficult or repeated pieces already exist in the base class.

In a class hierarchy, the base class sits above the derived classes and the arrow points from base to derived. The arrow reflects dependence: the derived class depends on what the base class offers. In the source's pair of classes, Circle is the base class that provides functions and data, and Smiley is the derived class that makes use of them.

Data Members and Constructors as Shared Work

The source notes that base classes in implementation inheritance often have data members and constructors. These two kinds of content are what derived classes can reuse, so it helps to know what each one is.

  • A data member is a stored value that belongs to the class.
  • A constructor is the function that sets up a new object when it is created.
  • A function such as Circle::draw() holds drawing behavior that a derived class can call instead of rewriting.

Because the base class already holds these pieces, a derived class can benefit from them without rewriting them. Drawing a shape, setting up its starting values, and storing its position are the kinds of work the source describes as often being the same across several related classes.

What a Smiley Object Contains

The source uses Smiley and Circle to show implementation inheritance. Smiley makes use of two things from Circle: Circle's constructor and Circle's draw function, written Circle::draw(). Smiley does not have to write its own version of either, because it can rely on the base class. The diagram below shows the parts of a Smiley that come from Circle and the part that Smiley adds itself.

Circlebase classconstructorsets up new objectsSmileyderived classdraw()drawing behaviordata membersstored valuessmiley-specific codeadded by Smileyprovidesprovidesprovidesbase foradds
Which parts of a Smiley object come from Circle, and which parts are added by Smiley itself? The base class supplies the constructor, the draw function, and the data members, while Smiley adds its own smiley-specific code.

The diagram shows the two sources of help flowing into Smiley. The constructor contributes setup, and the draw function contributes drawing behavior. Smiley is the place where these reused parts are brought together with whatever is specific to a smiley.

Tracing a Smiley Through Run Time

Reuse is easiest to see by following what happens while the program runs. Two moments matter in the Smiley example. The first is when a Smiley object is created, because Smiley uses Circle's constructor to set itself up. The second is when code asks a Smiley to draw itself, because Smiley relies on Circle::draw(). In both moments, control moves from the derived class's code into the base class's code, and the work carries on from there.

Calling codeSmileyCirclecreate Smileyuses constructorrequest drawCircle::draw()
When a Smiley object is created and drawn, in what order do the Smiley and Circle code run, and which calls go up to Circle? Read the arrows from top to bottom.
Worked example

Following One Smiley From Creation to Drawing

Code creates one Smiley and then asks it to draw itself. Which code runs at each step, and where does control go into Circle?

  1. 1
    Create the Smiley

    The calling code requests a new Smiley object. Smiley needs to be set up, so it uses Circle's constructor. Control moves from Smiley's code into Circle's constructor.

  2. 2
    Return to the new object

    Once the reused constructor has done its setup work, the new Smiley object exists and is ready to be used. The derived class did not need its own copy of the setup code.

  3. 3
    Request a draw

    The calling code asks the Smiley to draw itself. Smiley relies on Circle::draw() for drawing, so control passes into Circle's draw function.

  4. 4
    Finish the drawing

    The work of Circle::draw() runs in the base class where that code lives. Smiley supplies what is specific to a smiley, and the reused drawing behavior carries out the shared part.

Result

Two calls from outside, create and draw, each pass control into Circle. Smiley contains no separate copy of the constructor or of Circle::draw(); the derived class reuses the base class's code at the moment it is needed.

Read the trace as two separate moments. When a Smiley is created, the work passes to the Circle constructor. When drawing is requested, the work passes to Circle::draw(). In each case the derived class does not need its own copy of the code, because the call goes to the base class where that code lives.

Mistakes About What a Derived Class Gets

A common mistake is to picture the derived class as holding its own full copy of everything the base class does. The source's example shows a different picture: Smiley relies on Circle's constructor and Circle::draw(), and control moves into Circle when those are needed. The table below compares the two pictures.

Common assumptionWhat the Smiley example shows
Smiley holds its own copy of the drawing codeSmiley relies on Circle::draw(), and control moves into Circle's code
Each derived class rewrites the shared setupSmiley uses Circle's constructor to set itself up
The base class only describes what a derived class isThe base class also supplies working parts for implementation
Reuse means the base code is repeated in each classThe base code is written once and called from the derived class

Assumptions about inherited work compared with the Smiley and Circle example

  • Common mistake

    Thinking the derived class gets its own copy of the base class's constructor and functions

    What it looks like

    Assuming Smiley contains a duplicated version of Circle::draw() that it runs by itself

    Why it fails

    The source says Smiley relies on Circle::draw(), and control moves into the base class when that function is needed

    Do this instead

    Think of the derived class as calling into the base class's code at the moment that code is needed

  • Common mistake

    Treating the base class as only a description of what the derived class is

    Why it fails

    Implementation inheritance means the base class also supplies working parts that simplify the derived class

    Do this instead

    Look for the functions and data the base class already provides before writing them again in the derived class

Practice Tracing Reuse

EASY

A class Smiley is derived from a base class Circle. Explain, for both creating a Smiley and drawing a Smiley, which class's code runs and why the derived class does not need its own copy of that code.

Hints
  • Look at which two moments the source identifies: creation and drawing.
  • Ask which function or constructor Smiley is relying on in each moment.
  • Consider what the derived class contributes that is specific to a smiley.
MEDIUM

Suppose you add a third derived class, Frown, that also needs the same setup and drawing as Circle. Describe which shared work Frown would reuse from Circle and which work you would write specifically for Frown.

Hints
  • Shared work in this course's source includes setting up starting values and drawing a shape.
  • Work specific to a frown is the part that differs from the general circle behavior.

Why Shared Base Class Work Pays Off

Implementation inheritance lets a base class supply functions or data that simplify the implementation of derived classes. The Smiley and Circle example shows a derived class reusing both a constructor and a function, so the derived class can stay shorter and focus on what is specific to it.

Key Takeaways

  • Implementation inheritance means a base class provides functions or data that simplifies the implementation of derived classes.
  • Base classes in this sense often hold data members and constructors that derived classes can reuse.
  • In the Smiley and Circle example, Smiley reuses Circle's constructor and Circle::draw(), and control moves into the base class when those are needed.
  • A derived class does not hold its own copy of the reused base class code; it relies on the base class where that code lives.

Related concepts

More concepts starting with B