Benefits of Class Hierarchies
Implementation inheritance means a base class provides functions or data that simplifies the implementation of derived classes.
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?
Reveal 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
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.
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.
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?
- 1Create 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.
- 2Return 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.
- 3Request 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. - 4Finish 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.
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 assumption | What the Smiley example shows |
|---|---|
| Smiley holds its own copy of the drawing code | Smiley relies on Circle::draw(), and control moves into Circle's code |
| Each derived class rewrites the shared setup | Smiley uses Circle's constructor to set itself up |
| The base class only describes what a derived class is | The base class also supplies working parts for implementation |
| Reuse means the base code is repeated in each class | The 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 likeAssuming Smiley contains a duplicated version of Circle::draw() that it runs by itself
Why it failsThe source says Smiley relies on Circle::
draw(), and control moves into the base class when that function is neededDo this insteadThink 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 failsImplementation inheritance means the base class also supplies working parts that simplify the derived class
Do this insteadLook for the functions and data the base class already provides before writing them again in the derived class
Practice Tracing Reuse
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.
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.