# Is a Circle a kind of an Ellipse in C++?

01 Dec 2016I stumbled upon this question while reading about inheritance in C++.
The problem is described there in detail, and the author gives good reasons
why a `Circle`

is not a kind of an `Ellipse`

.
The main argument is that you may end up with
non-round circles if you inherit `Circle`

from `Ellipse`

.

Indeed, if `Circle`

derives from `Ellipse`

, you can refer to a circle
through a reference to an ellipse `Ellipse&`

.
Once you have such a reference,
you can do evil things to your poor little circle.
For example, you may resize it asymmetrically!
That wouldn’t be nice, would it? But why do we come to such result? It feels so
natural that a circle is just a special kind of an ellipse. In the end,
every book on C++ has an example with `Circle`

inheriting from `Shape`

and
`Smiley`

inheriting from `Circle`

, and everything works like charm
in the textbooks.

To get to the root of all evil, let’s formulate the problem in clear mathematical terms.

## Circles and ellipses as sets of points

What is a circle?

I always find it easier to parse such definitions when they are written in the set-builder notation. A circle of radius $a \in \mathbb{R}$ is

Similarly, an **ellipse** with semi-axes
$a \in \mathbb{R}$ and $b \in \mathbb{R}$ is

In C++ terminology, $C_a$ is an object of type `Circle`

for every fixed $a$.
Analogously, $E_{a,b}$ is an object of type `Ellipse`

for every fixed pair $\left(a, b\right)$.

## Types in C++ as sets of objects

Circles of different radius are different objects.
One might be tempted to think about an object as being a persistent entity,
but that mode of thinking is erroneous.
For example, say, we have a circle `c`

of radius $1$, and we call
`c.size(5)`

to set its radius to $5$. Did we just create a new object or did
we modify an existing one? The correct answer is that we have created a new
object. It doesn’t matter that on the implementation level we just
changed a few bits at the same memory location where our old object resided.
What does stay the same, however, is the variable `c`

that
acts like a box in which we are putting our objects.
The language itself should be your guide.
When you define `int i = 1;`

, you create a “*variable* of type `int`

”, meaning
that `i`

denotes a box for objects of type `int`

.

Alright, we now understand that a variable is an imaginary box that can hold objects of a certain type. What is a type then?

Imagine you want to declare a new type called `Bool`

. By our definition, you
have to provide a set of values that a `Bool`

can take. That is easy to do,
since those are just `0`

and `1`

. In addition to that, you need to declare
what one can do with those values; in other words, you have to declare
functions like `&&`

, `||`

, `<<`

, and so on. Notice that all functions that
can do something on $V$ are part of the type—not only the functions
from $V$ to $V$. That is, `void print(Bool)`

and `Bool::from_int(int)`

,
for instance, belong to $F$, despite the fact that the codomain of the former
is the empty set and the domain of the latter is `int`

.

Thus, a type is a set of objects together
with a set of mappings *from* and *to* the set of objects.

## Circle and Ellipse types

We have defined a circle of radius $a$ in \eqref{circle}. Let’s now form the set of all circles

Analogously for ellipses \eqref{ellipse},

Every circle $C_a$ lives in the family of circles $C$,
and every ellipse $E_{a,b}$—in the family of ellipses $E$. Therefore,
we can identify the type `Circle`

with the set $C$,
and the type `Ellipse`

with the set $E$.
Then, to say that an object $c$ is of type $C$ simply means $c \in C$.

## Inheritance in C++ as supersetting

A word about inheritance is in order. We are only concerned with `public`

inheritance here. By definition, a derived type is a strict superset
of the base type it derives from.

Every object of type Derived includes Base as a subobject.

That is, a child can do everything a parent can do, plus something extra.

There are, unfortunately, some quirks in terminology
due to the fact that a derived type
is a *superset* and not a subset of the base type.
Namely, *it is wrong to call a derived type a subtype of the base type*,
because it is, in fact, a supertype. Example: let $B$ and $D$ be types, and
let $D$ be derived from $B$; then $B \subset D$. In other words,
if we identify `Base`

with $B$ and `Derived`

with $D$,
then `Base`

is a subtype of `Derived`

. This is, by the way, why
$D$ is called “derived class” and not “subtype” of $B$.

## Maybe an Ellipse is a kind of a Circle?

At this point, it should be apparent that $C$ is a subset of $E$, $C \subset E$.
Indeed, you can find every imaginable circle in the set of ellipses. But by
definition of inheritance, it means precisely that $E$ inherits from $C$!
In other words, `Ellips`

derives from `Circle`

(or equivalently,
`Circle`

is a subtype of `Ellipse`

).
So, we should inherit `Ellipse`

from `Circle`

and not the other way around!

Wait a second. Does this imply that an ellipse is a kind of a circle then?

## Relation “is a kind of” is ill-defined

There is no answer to this question, because the relation “is a kind of” is
ill-defined. You can say that a circle is a round ellipse, or you can say
that an ellipse is an oblate circle. Think about `int`

and `double`

.
You can say that `double`

is an `int`

with higher precision, or you can say
that `int`

is a less precise `double`

.
Therefore, the question whether a `Circle`

is a kind of an `Ellipse`

does not make sense.

But that does not mean that the whole discussion was futile.
One of the big advantages of class hierarchies is in enabling
substitution of a `Base`

object in place of a `Derived`

object.
In our case, a meaningful question would be
“Should `Circle`

derive from `Ellipse`

or the other way around?”
And this is the question that we were actually able to answer.

## Does Ellipse have `radius()`

?

We have figured out that, from an abstract point of view, `Ellipse`

should
derive from `Circle`

. If you look closely at the argument, though, you will
notice that I cheated a bit. I considered `Circle`

and `Ellipse`

as
pure value types, meaning that there are no functions defined on them:
$C = (V, \emptyset)$ and $E = (W, \emptyset)$, where $V$ and $W$ are value sets.
But classes without functions would be totally useless,
so now it’s time to get rid of this simplifying assumption.

Let’s allow `Circle`

and `Ellipse`

to have methods. Since `Ellipse`

inherits
from `Circle`

, most of them should be virtual. Indeed, formulas for the
arc length and for the surface area are more complicated for the `Ellipse`

,
and it would be a waste of resources calculating the circumference of a `Circle`

using the elliptic integral of the second kind,
despite it yielding the correct result.

Ok—you might say—and
what about the methods that `Circle`

has but `Ellipse`

doesn’t?
For example, what should `Circle::radius()`

return for an `Ellipse`

?
If someone is calling `radius()`

on an ellipse, the ellipse is apparently
treated as a circle; since `Ellipse`

has two parameters while `Circle`

requires only one, you can pick any of the two and use it as radius.
If you additionally make sure that `Ellipse::radius(float r)`

sets both
$a$ and $b$ to $r$, you can switch between viewing an `Ellipse`

as an `Ellipse`

and as a `Circle`

in a consistent way.

## Mind the application during design

Is it worth using inheritance at all in this case? If I have to redefine all
methods of `Ellipse`

,
why bother inheriting from `Circle`

in the first place?
And this is a valid point. The answer depends on the application, however.
In some cases, it is better to derive them both from a common ancestor.
In other cases, it is better to define a
suitable Concept that they both satisfy. The final decision should be dictated
by the needs of the application.