I have an abstract class Node
that can either be a Leaf
or a NonLeaf
. I have written a large function SplitNode
. The problem is, this function is basically the same for a Leaf
as for a NonLeaf
. The only difference being that it operates on the entries
vector for Leaf
s, as opposed to the children
vector, for NonLeaf
s. The code is otherwise identical in both cases. For example in one case I do entries[i]->r
to access some Rectangle
property, and in the other case I do children[i]->r
. So the main difference beyond the 2 variable names, is the type of the actual vector. How am I supposed to implement this, without copying and pasting the same function, implemented slightly differently for Leaf
and NonLeaf
?
Edit: I also want the SplitNode
function to be able to be called recursively.
class Leaf;
class Node
{
public:
Node();
virtual Leaf& ChooseLeaf(const Rectangle& entry_r) = 0; // this makes the Node class Abstract
Rectangle r;
unique_ptr<Node> parent;
};
class Leaf : public Node
{
public:
Leaf();
Leaf& ChooseLeaf(const Rectangle& entry_r) override;
vector<unique_ptr<IndexEntry>> entries;
};
class NonLeaf : public Node
{
public:
NonLeaf();
Leaf& ChooseLeaf(const Rectangle& entry_r) override;
vector<unique_ptr<Node>> children;
};
Dummy illustration of the SplitNode()
function:
void SplitNode()
{
// in the Leaf case:
if (this.entries.size() > rtree.M)
{ ... }
// in the NonLeaf case:
if (children.size() > rtree.M)
{ ... }
// in the Leaf case:
entries[0]->r.DoSomething();
// in the NonLeaf case:
children[0]->r.DoSomething();
// Recursion
parent.SplitNode();
...
|
CodePudding user response:
This is a textbook case for a template function. Presuming that the common logic freestanding logic whose only dependency is the vector itself:
template<typename T>
void doSplitNode(T &entries_or_children)
{
for (auto &entry_or_child:entries_or_children)
{
auto &the_r=entry_or_child->the_r;
// Here's your entries[i]->r, or children[i]->r
}
}
// ...
class Leaf : public Node
{
public:
// ...
void SplitNode()
{
doSplitNode(entries);
}
};
class NonLeaf : public Node
{
// ...
void SplitNode()
{
doSplitNode(children);
}
};
Additional work will be needed of the shared logic has additional dependencies. There's no universal solution here, everything depends on the details. Perhaps the template itself can be moved into a class, with both NonLeaf
and Leaf
multiply-inheriting from it, and then implementing the additional dependencies as virtual/abstract methods.