Triangle(Point p1, Point p2, Point p3); // calculate center
// ...
};
Problems:
* As the hierarchy grows and more data is adder to `Shape`, the constructors gets harder to write and maintain.
* Why calculate the center for the `Triangle`? we may never us it.
* Add a data member to `Shape` (e.g., drawing style or canvas)
and all derived classes and all users needs to be reviewed, possibly changes, and probably recompiled.
The implementation of `Shape::move()` is an example of implementation inheritance:
we have defined 'move()` once and for all for all derived classes.
The more code there is in such base class member function implementations and the more data is shared by placing it in the base,
the more benefits we gain - and the less stable the hierarchy is.
##### Example
???
This Shape hierarchy can be rewritten using interface inheritance:
class Shape { // pure interface
public:
virtual Point center() const =0;
virtual Color color() const =0;
virtual void rotate(int) =0;
virtual void move(Point p) =0;
virtual void redraw() =0;
// ...
};
Note that a pure interface rarely have constructors: there is nothing to construct.
class Circle : public Shape {
public:
Circle(Point c, int r, Color c) :cent{c}, rad{r}, col{c} { /* ... */ }
Point center() const override { return cent; }
Color color() const override { return col; }
// ...
private:
Point cent;
int rad;
Color col;
};
The interface is now less brittle, but there is more work in implementing the member functions.
For example, `center` has to be implemented by every class derived from `Shape`.
##### Example, dual hierarchy
How can we gain the benefit of the stable hierarchies from implementation hierarchies and the benefit of implementation reuse from implementation inheritance.
One popular technique is dual hierarchies.
There are many ways of implementing the ide of dual hierarchies; here, we use a multiple-inheritance variant.
First we devise a hierarchy of interface classes:
class Shape { // pure interface
public:
virtual Point center() const =0;
virtual Color color() const =0;
virtual void rotate(int) =0;
virtual void move(Point p) =0;
virtual void redraw() =0;
// ...
};
class Circle : public Shape { // pure interface
public:
int radius() = 0;
// ...
};
To make this interface useful, we must provide its implementation classes (here, named equivalently, but in the `Impl` namespace):
class Impl::Shape : public Shape { // implementation
public:
// constructors, destructor
// ...
virtual Point center() const { /* ... */ }
virtual Color color() const { /* ... */ }
virtual void rotate(int) { /* ... */ }
virtual void move(Point p) { /* ... */ }
virtual void redraw() { /* ... */ }
// ...
};
Now `Shape` is a poor example of a class with an implementation,
but bare with us because this is just a simple example of a technique aimed at more complex hierrchies.
class Impl::Circle : public Circle, public Impl::Shape { // implementation
publc:
// constructors, destructor
int radius() { /* ... */ }
// ...
};
And we could extend the hierarchies by adding a Smiley class (:-)):
class Smiley : public Circle { // pure interface
public:
// ...
};
class Impl::Smiley : Public Smiley, public Impl::Circle { // implementation
Since each implementation derived from its inteface as well as its implementation base class we get a latice (DAG):
Smiley -> Circle -> Shape
^ ^ ^
| | |
Impl::Smiley -> Impl::Circle -> Impl::Shape
As mentioned, this is just one way to construct a dual hierarchy.
Another (related) technique for separating interface and implementation is [PIMPL](#???).
##### Note
There is often a choice between offering common functionality as (implemented) base class funcetions and free-standing functions
(in an implementation namespace).
Base classes gives a shorter notation and easier access to shared data (in the base)
at the cost of the functionality being available only to users of the hierarchy.
##### Enforcement
???
* Flag a derived to base conversion to a base with both data and virtual functions
(except for calls from a derived class memvber to a base class member)
* ???
### <aname="Rh-copy"></a>C.130: Redefine or prohibit copying for a base class; prefer a virtual `clone` function instead
@ -7015,7 +7214,8 @@ Naked unions are a source of type errors.
# <aname="S-enum"></a>Enum: Enumerations
Enumerations are used to define sets of integer values and for defining types for such sets of values. There are two kind of enumerations, "plain" `enum`s and `class enum`s.
Enumerations are used to define sets of integer values and for defining types for such sets of values.
There are two kind of enumerations, "plain" `enum`s and `class enum`s.