views:

238

answers:

3

i am currently implementing a binary tree in c++ and i want to traverse it with a function called in_order().

is there any way to pass a function as an argument, so that i can do things like below (without having to write the code to traverse the list more than once)?

struct tree_node; // and so on
class  tree;      // and so on

void print_node () {
  // some stuff here
}

// some other functions

tree mytree();

// insert some nodes

mytree.in_order(print_node);
mytree.in_order(push_node_to_stack);
mytree.in_order(something_else);
+12  A: 

Yes, you can do this in a number of ways. Here are two common possibilities.

Old-style function pointers

class mytree
{
    // typedef for a function pointer to act
    typedef void (*node_fn_ptr)(tree_node&);

    void in_order(node_fn_ptr)
    {
        tree_node* pNode;

        while (/* ... */)
        {
        // traverse...
        // ... lots of code

        // found node!
            (*fnptr)(*pNode);
            // equivalently: fnptr(*pNode)
        }
    }
};

void MyFunc(tree_node& tn)
{
    // ...
}

void sample(mytree& tree)
{
    // called with a default constructed function:
    tree.inorder(&MyFunc);
    // equivalently: tree.inorder(MyFunc);
}

Using functors

With a template member, works with function pointers

class mytree
{
    // typedef for a function pointer to act
    typedef void (*node_fn_ptr)(tree_node&);

    template<class F>
    void in_order(F f)
    {
        tree_node* pNode;

        while (/* ... */)
        {
        // traverse...
        // ... lots of code

        // found node!
            f(*pNode);
        }
    }
};

struct ExampleFunctor
{
    void operator()(tree_node& node)
    {
        // do something with node
    }
}

void sample(mytree& tree)
{
    // called with a default constructed function:
    tree.inorder(ExampleFunctor());
}
Charles Bailey
+1 You beat me by 30s ;)
AraK
@AraK: I was typing as fast as I could...
Charles Bailey
thanks, really helped me a lot!
padde
+1: hoping the OP will use the new style rather the C-style :)
Matthieu M.
+1 - It may be worth adding a note explaining the pros and cons of these two methods though. (functors can store state, and are easier inlined by the compiler)
jalf
A: 

Yes, you can use a function pointer as a parameter to in_order. You may also need to overload it, in case the passed functions' signatures don't match. For functions like print_node, declare in_order like this (provided its return type is void as well):

void tree::in_order( void (*)() )
{
   //implementation
}
zdawg
A: 

I think you should use the visitor pattern instead.

http://en.wikipedia.org/wiki/Visitor%5Fpattern

The base visitor class should have a virtual method to operate on a node. Pass the visitor as an argument to your in_order method. Then derive your visitor as many times as you want for any operation you want to do.

Julio
Actually the visitor pattern is probably more powerful than what you actually want to achieve. The strategy pattern should suffice.http://en.wikipedia.org/wiki/Strategy_pattern
Julio
it's both not quite what i was looking for. i think that both would be too bloated for a small binary tree class. interesting concepts, though!
padde
Yeah a little bit more bloated, but probably more powerful.And when I work in C++ I try to avoid at all cost static functions.
Julio