Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to deal with "super" calls and recursion

My question is about merging 2 techniques:

  • Call recursively to super functions
  • Call recursively to the same function

Suppose a root class that has a recursive function (foo), and a extended class that override this function ( foo): the override function must call super::foo, but require to perform other operations before to call recursively.

I will try an example (it is only an example, and I know there is non-recursive way to solve this problem)

class Node
{
public:
    // must be override
    virtual int getNumValues()
    {
        if (parent) return parent->getNumValues() + 3;
        else return 3; 
    }
protected:
    Node *parent;
private:
    int values[3];
};

class ExtNode: Node
{
public:
    //@override
    virtual int getNumValues()
    {
        int aux = Node::getNumValues(); //but need to avoid recursion here.
        if (parent) return parent->getNumValues() + aux + 2;
        else return aux + 2;
    }
private:
    int extValues[2];
};

So what I would is:

  • I may change both classes: Node and ExtNode.
  • I would not to copy the code from the first class method to the second to avoid Super call (the class chain may be long)
  • The recursive call should probably be done by the childest class

I am trying some ideas, but they seem poor programming practice or not possibles:

// In Node class
...
virtual int getNumValues()
{
    if (parent && !isNodeObject(this)) return parent->getNumValues()+3;
    else return 3;
}
bool isNodeObject( Node *ob)
{
    //return if ob is instance of Node (and not an extended class). How?
}

I have also tried with optional parameters:

// In Node class
...
virtual int getNumValues( bool recursion = true)
{
    if (parent && recursion) return parent->getNumValues()+3;
    else return 3;
}  

// In ExtNode class
...
virtual int getNumValues( bool recursion = true)
{
    int aux = Node::getNumValues(false );
    if (parent && recursion) return parent->getNumValues() + aux + 2;
    else return aux + 2;
}

What is the best programming practice for that?

EDIT 1: Explanation of the real problem I am trying to resolve (asked from Joachim Pileborg)

I am creating a User interface library, that is, a set of classes and function to create easily widgets like frame, buttons, input texts, etc.

I have created a basic (root class) widget with most general features, a "Visible" widget to implement all generic functions for widgets that has a visible part, and soo on.

There are also some containers, like frames, layout and windows.

Now come the hard part: there is a function "updateStyle" that is supposed to update at once all the graphic part of the widget (and redraw it): this function call recursively to super class to perform more generic features, and also has to call recursively to containers to propagate changes (dimensions and positions of widgets may change)

enter image description here

Each widget is supposed to work "as this" and also to be extendable, that is why these requirements.

Code is extensive (about 8k lines) and has a lot of other features, so no point to copy here the code.

like image 782
Adrian Maire Avatar asked Jul 23 '14 12:07

Adrian Maire


1 Answers

It looks like you are searching for the template method pattern:

  • in the base class, implement a nonvirtual method that outlines the general behavior of the function.
  • define (abstract) virtual methods that define the special behavior parts inside that function
  • in derived classes, override the special behavior

    class Node
    {
    public:
      int getAllNumValues()
      {
        int allNumValues = getNumValues();
    
        if (parent) allNumValues += parent->getAllNumValues();
    
        return allNumValues; 
      }
    
    protected:
      virtual int getNumValues() {
         return 3;
      }; 
    private:
      Node *parent;
      int values[3];
    };
    
    class ExtNode: Node
    {
    protected:
      //@override
      virtual int getNumValues()
      {
        return 2 + Node::getNumValues(); //but need to avoid recursion here.
      }
    private:
      int extValues[2];
    };
    

in case of your update functionality I'd suggest to have a template method update that does the recursive updating of your composite pattern, and another method updateThis that does updating of only the single object.

like image 96
Arne Mertz Avatar answered Oct 04 '22 07:10

Arne Mertz