This is mixin as Jannis Smaragdakis calls it.
// Mixin
template <class Base>
class Mixin : public Base { ... };
class Base { ... };
The interesting thing is, that in normal object-oriented style base is always implemented before derived. Here we can implement inheritance delaying the definition of the base.
//
// suppose Graph has succ_node() and succ_edge()
//
template <class Graph>
class Counting : public Graph
{
public:
Counting() : nodes_visited(0), edges_visited(0) { }
node succ_node( node v)
{
++nodes_visited;
return Graph::succ_node(v);
}
node succ_edge( node v)
{
++edges_visited;
return Graph::succ_edge(v);
}
private:
int nodes_visited;
int edges_visited;
};
Counting< Ugraph > counted_ugraph;
Counting< Dgraph > counted_dgraph;
Be care with the lazy instantiation:
//
// be care with lazy instantiation
//
template <class Sortable>
class WontWork : public Sortable
{
public:
void sort(X x)
{
Sortable::srot(x); // !!misspelled
}
};
WontWork w;
If the client never calls w.sort there is no error message!
In 1977 Barbara Liskov defined her substitutional principle: an object from the subtype can appear in every place where its supertype's objects can. That is one of the most fundamental rule in object-orientation: a derived object can appear everywhere the base object can.
The problem is, that this does not hold for mixins.
lass Base { ... };
class Derived : public base { ... };
template <class T> class Mixin : public T { ... };
Base b;
Derived d;
Mixin<Base> mb;
Mixin<Derived> md;
b = d // OK
mb = md; // Error!
We have seen a similar situation with auto_ptr. The auto_ptr<Derived> does not konvertible to auto_ptr<Base>.