Home > OS >  Implement a virtual function for two derived classes, that is the same except for one variable Type
Implement a virtual function for two derived classes, that is the same except for one variable Type

Time:09-06

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 Leafs, as opposed to the children vector, for NonLeafs. 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.

  • Related