Interfaces and Abstract Base Contracts
An abstract class is not meant to be instantiated on its own. It exists to serve as a base for other classes.
A Drawing Program with Many Kinds of Figures
Imagine you are building a drawing program. Users can place circles, squares, and triangles on a canvas, and the program needs to keep all of them in one collection. Each figure is different, yet the program must process every item in that collection. The natural question is how to write a single function that handles every item without writing a separate function for each kind of figure.
What do you think happens?
Before reading on, predict: if Shape is the common base of Circle and Square, should the program be allowed to create a plain Shape object directly, such as a generic shape sitting on the canvas?
Reveal answer
No. There is no such thing as a generic shape sitting in a drawing. Every real shape is a particular kind of shape, such as a circle or a square.
This is why Shape is designed as an abstract class. Its job is to name the common idea of a shape and to serve as the base that specific figures build on, not to be created on its own.
Tracing a Loop Over Shape Pointers
The collection cannot hold the figures themselves as one uniform kind of value, because a circle and a square are different kinds of things. Instead, the collection holds pointers to shapes. Each pointer refers to some concrete figure, whether that figure is a circle, a square, or a triangle. The collection is uniform even though the figures are not: every element is a pointer to a Shape.
Trace the diagram step by step. The loop takes one pointer from the collection. That pointer refers to some concrete figure, so the call to draw() is made through the Shape interface. The program does not need to know in advance whether the pointer points to a circle or a square. It only needs to know that the pointer leads to a Shape and that every Shape supports the operations the abstract class promises. The choice of which draw() runs is made for each element as the loop reaches it.
- 1Shape declares
draw()as a contract without giving it a body. - 2Circle and Square each inherit from Shape and complete the contract with their own
draw(). - 3
drawAllaccepts a vector of Shape pointers and never names Circle or Square. - 4Each s->
draw()call is resolved to the concrete figure that the pointer refers to.
- The = 0 marks
draw()as a promise that every derived class must complete - Circle and Square each bring their own stored fields
drawAllworks for any collection of Shape pointers, including figures added later
What Makes a Class Abstract
An abstract class is not meant to be instantiated on its own. It exists to serve as a base for other classes. Shape is the standard example: it names the shared idea of a shape, and specific figures such as circles and squares are the classes that are actually used as objects.
The word contract is useful here. The abstract base states what every shape can do, and the derived classes must honor that statement. A function that receives a Shape pointer relies on this promise. It does not need to know how the promise is kept for a particular figure, only that the promise is kept. This is why the abstract base can be described as a shared interface rather than a shared implementation.
The diagram shows the relationship between kinds. It does not show the fields inside each figure. The abstract base sits above the derived classes as the shared name and the shared contract, while the details stay specific to each kind. This is the reason an abstract class cannot be created on its own: a shape that is not a particular kind of shape has no concrete details to describe it.
Why Shape Stores Almost Nothing in Common
It is tempting to think of a base class as a template that fills in fields for every subclass. A circle has a radius, a square has a side length, and a triangle has three sides, so one might expect a common base to hold a shared set of numbers. The abstract class idea runs the other way. The source states the point directly: as far as representation is concerned, nothing except the location of the pointer to the vtbl is common for every Shape. The Shape part of each object carries no common fields that all shapes must store in the same way.
Read the two columns as the memory layouts of a Circle and a Rectangle. The only part that both objects share in this contract is the vtbl pointer, the location that leads to the table of virtual functions. Everything else, such as the radius of a circle or the width and height of a rectangle, belongs to the specific figure. The base therefore provides a shared interface rather than shared stored data. What the derived classes have in common is the way they are used, not a common layout of values.
Because of this design, one general function can manipulate a vector of pointers to shapes, whatever concrete figures those pointers refer to. The function does not depend on the stored fields of any figure. It depends only on the operations promised by the abstract class.
Mistakes Beginners Make with Abstract Bases
Common mistake Assuming a base class must hold the shared data for all its subclasses
What it looks likePutting a radius field in Shape because circles have one, then expecting squares to use it too
Why it failsThe source states that nothing except the location of the pointer to the vtbl is common for every Shape. Each figure's details differ too much to share one layout.
Do this insteadUse the abstract base to name the shared operations, and keep the stored details in each derived class.
Common mistake Trying to create a Shape object directly so that it can be placed on the canvas
What it looks likeWriting a plain Shape object as a stand-in for a figure the user has not chosen yet
Why it failsAn abstract class is not meant to be instantiated on its own. A generic shape is not a real figure in a drawing.
Do this insteadCreate a concrete figure such as a Circle or a Square and store a pointer to it in the collection.
Common mistake Writing a separate function for each kind of figure in the collection
What it looks likeOne function for drawing circles, another for drawing squares, and another for triangles, all over the same canvas
Why it failsThis repeats the work and ignores the purpose of the shared base, which lets one general function handle any Shape pointer.
Do this insteadWrite one function that takes a collection of Shape pointers and calls the shared operation on each element.
Practice: Tracing the Shape Contract
A drawing program stores a collection of pointers that refer to a Circle, a Square, and a Triangle, in that order. A general function loops over the collection and calls draw() on each element. Explain, for each element, which kind of object the call reaches and what information the function needed in order to make the call. Then explain why the function would still work if a fourth kind of figure were added later.
Hints
- Look at the collection: every element is a pointer to a Shape, not a Circle or Square.
- Think about what the abstract base promises, and what the function does not need to know.
- Consider the phrase: the function only needs to know that each pointer leads to a Shape.
Reviewing the Contract Idea
- 1An abstract class is not meant to be instantiated on its own. It exists to serve as a base for other classes, such as Shape for circles and squares.
- 2Shape provides a shared interface rather than shared stored data: as far as representation is concerned, only the location of the pointer to the vtbl is common for every Shape.
- 3A collection holds pointers to shapes, so every element has the same type even though the figures differ.
- 4One general function can loop over Shape pointers and call the promised operations, without knowing which concrete figure each pointer refers to.
Key Takeaways
- An abstract class is not meant to be instantiated on its own; it exists to serve as a base for other classes.
- Shape is the standard example, because every real figure is a particular kind of shape.
- Shape provides a shared interface, not shared data: only the location of the pointer to the vtbl is common for every Shape.
- A collection of Shape pointers lets one general function process any figure without a separate function for each kind.