Consider the following implementation of a graph, whose nodes must be of
type Node or of a subclass of Node:
class Node {
public:
Node(Data* d) { adjList = new vector<Node*>; data = d; }
virtual ~Node() { delete adjList; }
virtual void addNode(Data* d) { /*...*/ }
void connectToNode(Node* n) { adjList->push_back(n); }
Node* getChild(int i) const { return adjList->at(i); }
// etc...
protected:
vector<Node*>* adjList;
Data* data;
};
class GraphBase {
protected:
GraphBase() { adjList = new vector<Node*>(); }
~GraphBase() { /* Free adjacency list */ }
void addNode(Data* d) { adjList->push_back(new Node(d)); }
void addEdge(Node* s, Node* t) { s->connectToNode(t); }
Node* getNode(int i) const { return adjList->at(i); }
Node* getFirstNode() const;
Node* getNextNode() const;
/* etc... */
private:
vector<Node*>* adjList;
int currentNode;
};
template <class NodeType>
class Graph : private GraphBase {
public:
Graph() : GraphBase() { }
~Graph;
void addNode(Data* d) { GraphBase::addNode(d); }
void addEdge(Node* s, Node* t) { GraphBase::addEdge(s, t); }
NodeType* getNode(int i) const { return (NodeType*)GraphBase::getNode(
i); }
NodeType* getFirstNode() const;
NodeType* getNextNode() const;
/* etc... */
};
class SpecialNode : public Node { SpecialNode* foo(); /* etc... */ };
class SpecialGraph : public Graph<SpecialNode> { /*...*/ };
I have a few questions about the previous partial code:
1) Is there a better way of implementing Node, knowing that it will be
specialized? As it is, whenever one of the methods returning a Node* is
called, there probably must be an explicit cast to the correct subclass
in the caller code, e.g. an implementation of foo() might be
SpecialNode* foo() { return (SpecialNode*)adjList->at[0]; }
2) Using a template (Graph) privately inheriting from a class (GraphBase)
is the only way I found to constrain a user of a graph to instantiate
only graphs whose nodes are of type Node or of a subtype of it. Is there
a better way to accomplish that? If I wanted to hide the GraphBase class
to the world, could I make it an inner class of the template, instead of
inheriting from it?
3) A statement such as GraphBase* g = new Graph<SpecialNode>() is not
allowed, because the template has a private base (right?). Should I make
the destructor of GraphBase virtual anyway?
Thanks in advance for your attention and for any advice you will be so
kind to give me.
Nicola