Re: templates of derived classes
* Zeppe:
I have a tree. This tree is not a class, it's just a collection of tree
nodes. The tree nodes are templatized. So, basically:
class TreeNodeBase;
typedef boost::shared_ptr<TreeNodeBase> TreeNodePtr;
class TreeNodeBase
{
// impl.
};
template <class Item>
class TreeNode
: public TreeNodeBase
{
public:
TreeNode(const Item& item)
: TreeNodeBase()
, item_(item)
{
}
const Item& GetItem() const { return item_; }
Item& GetItemRef() { return item_; } // safer - explicit call
TreeNode<Item>* FindNode(const Item& item);
const TreeNode<Item>* FindNode(const Item& item) const;
template <class ItemIt, class ItemDistance>
static TreeNodePtr GenerateMinimumSpanningTree(ItemIt begin, ItemIt end);
private:
Item item_;
};
Ok?
Not quite. With the above structure you'd have to tentatively downcast
(via Boost's dynamic cast) each TreeNode-pointer to see what actual type
it is, i.e. to determine the type T in TreeNode<T>. Unless all nodes in
a tree have the same T, in which case TreeNodeBase doesn't make sense.
The question for a proper design is essentially: can a tree have nodes
with different item types?
If the nodes in a given tree can have different item types, I'd suggest
as best solution to require them to be derived from some common abstract
class (an interface class would be best), and otherwise, completely
unrelated types, using boost::any (if I recall the name correctly).
I can generate a minimum spanning tree from a set of elements by
GenerateMinimumSpanningTree, giving some forward iterators, and
specifying the distance class that i want to use to perform the weight
calculation.
Presumably this means that your Items are really graph nodes.
If so, then I suggest moving that factory function out of TreeNode.
It doesn't generate a TreeNode, it generates a Tree.
In order to generate the MinimumSanningTree, the
GenerateMinimumSpanningTree function will use the Tree constructor, in a
piece of code like:
std::vector<std::pair<TreeNodePtr, ItemIt> > trees;
for(ItemIt item = begin; item != end; ++item)
trees.push_back(std::make_pair(TreeNodePtr(new TreeNode<Item>(*item)),
item));
(the vector is used in the algorithm for the minimum spanning tree).
Presumably you mean "the TreeNode constructor".
Then, after I generate like this a tree, in a particular problem I need
a tree of Descriptors.
Once I generate this tree of descriptors passing the appropriate forward
iterators to the GenerateMinimumSpannigTree algorithm, I can give it to
a class that will perform some classification of this tree. Ok?
Not sure exactly what you mean.
Is it correct that you mean to generate a /corresponding/ tree of
descriptors?
Why not just put the descriptors in the TreeNodes, or if that is frozen
code, use a std::map to associate a descriptor with each TreeNode?
This
class will pass the tree to other members that have to perform some
calculation to perform the classification, that is, the tree will be
read by some functions, for example:
class FactorGraphSolver
{
public:
void SolveFor(QMUL::TreeNode<Descriptor>* node, unsigned categoryID,
unsigned partsLabelNumber);
// other things...
};
And I'm really fine with that function signature, because actually the
FactorGraphSolver needs just a Tree of Descriptors, nothing more,
nothing less.
Ok?
Seems OK. A separate tree of descriptors, describing the nodes of a
TreeNode tree, which itself is a minimum spanning tree for the Item
nodes in some graph.
Let's say that now I want to add a particular additional information
to that tree node, for example a reference to the real descriptor that
generated it, and a label. Then I'll pass to the classification class,
and this class will call the same usual subclasses to perform the
calculations and, once done, will label every node properly. At the end
of the function, I could explore the tree and, being composed of
descriptor that have a reference of the elements that have generated
them, I can label the original elements.
Huh? "real descriptor that generated it", what's that? You lost me.
Ok, the problem is this one. It seems to me that I've said enough to
understand it. I won't post the real code because it's long and mostly
unrelated to the problem.
As I understand it, just generate a parallel tree of descriptors.
I don't see how this ties in to having the factory function generate
nodes of some derived class.
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?