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>.