Motivation
Say I'm writing a Tree class. I will represent the nodes of the tree with the Tree::Node class. Class methods can return Tree::Node objects and treat them as arguments, such as a method that receives the parent element node: Node getParent(Node) .
I also need the SpecialTree class. SpecialTree should extend the Tree interface and be used anywhere in a Tree .
Behind the scenes, Tree and SpecialTree can have completely different implementations. For example, I could use the GraphA library GraphA to implement Tree , so Tree::Node is a thin wrapper or typedef for GraphA::Node . On the other hand, SpecialTree can be implemented in terms of a GraphB object, while Tree::Node wraps GraphB::Node .
Later I will have functions that deal with trees, for example, a depth search function. This function must accept interchangeable Tree and SpecialTree objects.
Sample
I use a template interface to define an interface for a tree and a special tree. The template argument will be the implementation class. For instance:
template <typename Implementation> class TreeInterface { public: typedef typename Implementation::Node Node; virtual Node addNode() = 0; virtual Node getParent(Node) = 0; }; class TreeImplementation { GraphA graph; public: typedef GraphA::Node Node; Node addNode() { return graph.addNode(); } Node getParent() {
Then I could get TreeInterface from TreeInterface :
template <typename Implementation> class SpecialTreeInterface : public TreeInterface<Implementation> { virtual void specialTreeFunction() = 0; };
And define TreeImplementation and TreeImplementation similarly to Tree and TreeImplementation .
My first depth search function might look like this:
template <typename T> void depthFirstSearch(TreeInterface<T>& tree);
and since SpecialTree comes from TreeInterface , this will work for Tree objects and SpecialTree objects.
Alternatives
An alternative is to rely more on templates so that SpecialTree not a descendant of TreeInterface in the type hierarchy at all. In this case, my DFS function will look like template <typename T> depthFirstSearch(T& tree) . It also produces a hard-coded interface that describes which methods a Tree or its descendants should have. Since SpecialTree should always act like a Tree , but provide some additional methods, I like using the interface.
Instead of the TreeInterface template TreeInterface , which is the implementation, I can force it to take a โpresentationโ class that defines what Node looks like (it will also need to determine what Arc looks like, and soon). But since I will potentially need one of them for each of the implementations, I think I would like to keep this together with the implementation class itself.
What can I get using this template? Basically, a weaker connection. If I wanted to change the implementation behind Tree , SpecialTree doesn't mind at all, because it only inherits the interface.
Questions
So, does this template have a name? I am using the handle-body template, storing a pointer to ContourTreeImplementation in ContourTree . But what about the approach to a templated interface? Does it have a name?
Is there a better way to do this? It seems like I am repeating and writing a lot of patterns a lot, but those nested Node classes give me problems. If Tree::Node and SpecialTree::Node had fairly similar implementations, I could define the NodeInterface interface for Node in TreeInterface and override the node class implementation in Tree and SpecialTree . But be that as it may, I cannot guarantee that this is true. Tree::Node can wrap GraphA::Node , and SpecialTree::Node can wrap an integer. So this method will not work, but it looks like there may still be room for improvement. Any thoughts?