views:

446

answers:

13

I've read through this article, and what I take from it is that when you want to call a pointer to a member function, you need an instance (either a pointer to one or a stack-reference) and call it so:

(instance.*mem_func_ptr)(..)
or
(instance->*mem_func_ptr)(..)

My question is based on this: since you have the instance, why not call the member function directly, like so:

instance.mem_func(..) //or: instance->mem_func(..)

What is the rational/practical use of pointers to member functions?

[edit]

I'm playing with X-development & reached the stage where I am implementing widgets; the event-loop-thread for translating the X-events to my classes & widgets needs to start threads for each widget/window when an event for them arrives; to do this properly I thought I needed function-pointers to the event-handlers in my classes.

Not so: what I did discover was that I could do the same thing in a much clearer & neater way by simply using a virtual base class. No need whatsoever for pointers to member-functions. It was while developing the above that the doubt about the practical usability/meaning of pointers to member-functions arose.

The simple fact that you need a reference to an instance in order to use the member-function-pointer, obsoletes the need for one.

[edit - @sbi & others]

Here is a sample program to illustrate my point: (Note specifically 'Handle_THREE()')

#include <iostream>
#include <string>
#include <map>


//-----------------------------------------------------------------------------
class Base
{
public:
    ~Base() {}
    virtual void Handler(std::string sItem) = 0;
};

//-----------------------------------------------------------------------------
typedef void (Base::*memfunc)(std::string);

//-----------------------------------------------------------------------------
class Paper : public Base
{
public:
    Paper() {}
    ~Paper() {}
    virtual void Handler(std::string sItem) { std::cout << "Handling paper\n"; }
};

//-----------------------------------------------------------------------------
class Wood : public Base
{
public:
    Wood() {}
    ~Wood() {}
    virtual void Handler(std::string sItem) { std::cout << "Handling wood\n"; }
};


//-----------------------------------------------------------------------------
class Glass : public Base
{
public:
    Glass() {}
    ~Glass() {}
    virtual void Handler(std::string sItem) { std::cout << "Handling glass\n"; }
};

//-----------------------------------------------------------------------------
std::map< std::string, memfunc > handlers;
void AddHandler(std::string sItem, memfunc f) { handlers[sItem] = f; }

//-----------------------------------------------------------------------------
std::map< Base*, memfunc > available_ONE;
void AddAvailable_ONE(Base *p, memfunc f) { available_ONE[p] = f; }

//-----------------------------------------------------------------------------
std::map< std::string, Base* > available_TWO;
void AddAvailable_TWO(std::string sItem, Base *p) { available_TWO[sItem] = p; }

//-----------------------------------------------------------------------------
void Handle_ONE(std::string sItem)
{
    memfunc f = handlers[sItem];
    if (f)
    {
        std::map< Base*, memfunc >::iterator it;
        Base *inst = NULL;
        for (it=available_ONE.begin(); ((it != available_ONE.end()) && (inst==NULL)); it++)
        {
            if (it->second == f) inst = it->first;
        }
        if (inst) (inst->*f)(sItem);
        else std::cout << "No instance of handler for: " << sItem << "\n";
    }
    else std::cout << "No handler for: " << sItem << "\n";
}

//-----------------------------------------------------------------------------
void Handle_TWO(std::string sItem)
{
    memfunc f = handlers[sItem];
    if (f)
    {
        Base *inst = available_TWO[sItem];
        if (inst) (inst->*f)(sItem);
        else std::cout << "No instance of handler for: " << sItem << "\n";
    }
    else std::cout << "No handler for: " << sItem << "\n";
}

//-----------------------------------------------------------------------------
void Handle_THREE(std::string sItem)
{
    Base *inst = available_TWO[sItem];
    if (inst) inst->Handler(sItem);
    else std::cout << "No handler for: " << sItem << "\n";
}


//-----------------------------------------------------------------------------
int main()
{
    Paper p;
    Wood w;
    Glass g;


    AddHandler("Paper", (memfunc)(&Paper::Handler));
    AddHandler("Wood", (memfunc)(&Wood::Handler));
    AddHandler("Glass", (memfunc)(&Glass::Handler));

    AddAvailable_ONE(&p, (memfunc)(&Paper::Handler));
    AddAvailable_ONE(&g, (memfunc)(&Glass::Handler));

    AddAvailable_TWO("Paper", &p);
    AddAvailable_TWO("Glass", &g);

    std::cout << "\nONE: (bug due to member-function address being relative to instance address)\n";
    Handle_ONE("Paper");
    Handle_ONE("Wood");
    Handle_ONE("Glass");
    Handle_ONE("Iron");

    std::cout << "\nTWO:\n";
    Handle_TWO("Paper");
    Handle_TWO("Wood");
    Handle_TWO("Glass");
    Handle_TWO("Iron");

    std::cout << "\nTHREE:\n";
    Handle_THREE("Paper");
    Handle_THREE("Wood");
    Handle_THREE("Glass");
    Handle_THREE("Iron");
}

{edit] Potential problem with direct-call in above example:
In Handler_THREE() the name of the method must be hard-coded, forcing changes to be made anywhere that it is used, to apply any change to the method. Using a pointer to member-function the only additional change to be made is where the pointer is created.

[edit] Practical uses gleaned from the answers:

From answer by Chubsdad:
What: A dedicated 'Caller'-function is used to invoke the mem-func-ptr;
Benefit: To protect code using function(s) provided by other objects
How: If the particular function(s) are used in many places and the name and/or parameters change, then you only need to change the name where it is allocated as pointer, and adapt the call in the 'Caller'-function. (If the function is used as instance.function() then it must be changed everywhere.)

From answer by Matthew Flaschen:
What: Local specialization in a class
Benefit: Makes the code much clearer,simpler and easier to use and maintain
How: Replaces code that would conventionally be implement using complex logic with (potentially) large switch()/if-then statements with direct pointers to the specialization; fairly similar to the 'Caller'-function above.

+11  A: 

The same reason you use any function pointer: You can use arbitrary program logic to set the function pointer variable before calling it. You could use a switch, an if/else, pass it into a function, whatever.

EDIT:

The example in the question does show that you can sometimes use virtual functions as an alternative to pointers to member functions. This shouldn't be surprising, because there are usually multiple approaches in programming.

Here's an example of a case where virtual functions probably don't make sense. Like the code in the OP, this is meant to illustrate, not to be particularly realistic. It shows a class with public test functions. These use internal, private, functions. The internal functions can only be called after a setup, and a teardown must be called afterwards.

#include <iostream>

class MemberDemo;
typedef void (MemberDemo::*MemberDemoPtr)();

class MemberDemo
{
    public:
    void test1();
    void test2();

    private:
    void test1_internal();
    void test2_internal();
    void do_with_setup_teardown(MemberDemoPtr p);
};

void MemberDemo::test1()
{
    do_with_setup_teardown(&MemberDemo::test1_internal);
}

void MemberDemo::test2()
{
    do_with_setup_teardown(&MemberDemo::test2_internal);
}

void MemberDemo::test1_internal()
{
    std::cout << "Test1" << std::endl;
}

void MemberDemo::test2_internal()
{
    std::cout << "Test2" << std::endl;
}

void MemberDemo::do_with_setup_teardown(MemberDemoPtr mem_ptr)
{
    std::cout << "Setup" << std::endl;
    (this->*mem_ptr)();
    std::cout << "Teardown" << std::endl;
}

int main()
{
    MemberDemo m;
    m.test1();
    m.test2();
}
Matthew Flaschen
In the article I link, the writer shows that the actual use of member-functions pointers are somewhat obscure, see section headed: "Uses of Member Function Pointers"
slashmais
+: If you want to invoke the member-function-ptr, you need a class-instance, but then you can as well call the member-function directly.
slashmais
@slash, he says it's only used for "contrived examples" and "delegates." Even if that is true, the article doesn't dispute that delegates are useful in a wide variety of applications.
Matthew Flaschen
@slash, again, you can always call a free function "directly" too. The considerations really aren't that different between regular and member function pointers. A regular function pointer can be called with parameters (assuming correct type). You can think of the instance as just an extra parameter (sometimes called the implicit parameter).
Matthew Flaschen
-1. Too useless.
Pavel Shved
I agree with Pavel, I don't think there is much value in this answer. The obvious followup is "Why would I want to do that, and how would I use a member function pointer?"
Omnifarious
@Omni, @Pavel, I've added an example. It's not realistic, but it's meant to demonstrate a case where virtual functions probably don't make sense.
Matthew Flaschen
@Mathew - That makes your answer a much better one.
Omnifarious
slashmais
+2  A: 

The use case is that you have several member methods with the same signature, and you want to build logic which one should be called under given circumstances. This can be helpful to implement state machine algorithms.

Not something you use everyday...

jdv
There's merit in what you suggest, but still ... Referring to the X-dev I'm busy with: linking the event, the widget, the parent-window and the method to call within this parent-window is a possible place for member-fp's.
slashmais
+1  A: 

There are many practical uses. One that comes to my mind is as follows:

Assume a core function such as below (suitably defined myfoo and MFN)

void dosomething(myfoo &m, MFN f){   // m could also be passed by reference to 
                                     // const
   m.*f();
}

Such a function in the presence of pointer to member functions, becomes open for extension and closed for modification (OCP)

Also refer to Safe bool idiom which smartly uses pointer to members.

Chubsdad
slashmais
The key to attaining OCP is to delink from the actual function name in the core function.
Chubsdad
@slashmais: what if you rename the member function to something else. If you bind to to name, this core function changes. But with the way I have shown, the name of the function does not matter. It is closed for modification and open for extension
Chubsdad
I understand what you are saying. A benefit your way would be if the particular function is used in many places, then you only need to change the name where it is allocated as pointer; if the function is used as instance.function() then it must be changed everywhere. Okay, this is at least one sensible use (+1).
slashmais
@slashmais: Yes, that's the heart of OCP. Core function is closed for modification and open for extension.
Chubsdad
slashmais
+1  A: 

This article describes some scenarios where pointers to member functions are useful.

Vijay Mathew
@sbi URL fixed :-)
Vijay Mathew
Looks like the best he can do is "... used to implement a different kind of polymorphism." This feels to me like he is trying to force something where it is not really appropriate: all that is achieved is a measure of obfuscation, you now have to drill down /how-many/ layers to find out what the code is doing.
slashmais
+2  A: 

Imagine for a second you have a function that could call one of several different functions depending on parameters passed.

You could use a giant if/else if statement
You could use a switch statement
Or you could use a table of function pointers (a jump table)

If you have a lot of different options the jump table can be a much cleaner way of arranging your code ...

Its down to personal preference though. Switch statement and jump table correspond to more or less the same compiled code anyway :)

Goz
my point is you need the instance - if you have the instance why do you need a func-pointer?
slashmais
Well I give you an example of when having a set of func pointers can be handy ...
Goz
But yeah .. you rarely NEED the func pointer. There is usually more than one way to skin a cat ...
Goz
+8  A: 

My question is based on this: since you have the instance, why not call the member function directly[?]

Upfront: In more than 15 years of C++ programming, I have used members pointers maybe twice or thrice. With virtual functions being around, there's not all that much use for it.

You would use them if you want to call a certain member functions on an object (or many objects) and you have to decide which member function to call before you can find out for which object(s) to call it on. Here is an example of someone wanting to do this.

sbi
slashmais
@slashmark: Read again, I even made the important part stand out! You need member function pointers when you want to decide which member function to call _before you can decide on which object to call it_. In the example I linked to, the decision about the function is made outside of `std::for_each()`, the decision about the objects inside of it.
sbi
@slash, first, the instance is a pointer to `Selector`, not a `Elem`. Second, `for_each` certainly is not going to execute something like `instance->prepare_elem(elem);` "directly", since it only knows how to execute a `UnaryFunction`. To *get* a `UnaryFunction`, you can first pass a *member function pointer* to `mem_fun`, then pass the result to `bind1st`.
Matthew Flaschen
@sbi - I've never used them directly, but I have frequently used them via `::boost::function` or `::std::tr1::function`.
Omnifarious
@sbi: I added an example program to my question to show what I mean.
slashmais
+4  A: 

I find the real usefulness of pointers to member functions comes when you look at a higher level construct such as boost::bind(). This will let you wrap a function call as an object that can be bound to a specific object instance later on and then passed around as a copyable object. This is a really powerful idiom that allows for deferred callbacks, delegates and sophisticated predicate operations. See my previous post for some examples:

http://stackoverflow.com/questions/1596139/hidden-features-and-dark-corners-of-stl/1596626#1596626

the_mandrill
It is a use for it, but you can at that point still call the member direct - no need for a pointer; a virtual base class will allow the same.
slashmais
The usefulness is that the calling code doesn't need to know about which function that is to be called, because you're passing the function as a parameter, eg see my previous example using `find_if()`.
the_mandrill
+3  A: 

The best use of pointers to member functions is to break dependencies.

Good example where pointer to member function is needed is Subscriber/Publisher pattern :

http://en.wikipedia.org/wiki/Publish/subscribe

VJo
+1  A: 

To invoke it, you need a reference to an instance, but then you can call the func direct & don't need a pointer to it.

This is completely missing the point. There are two indepedent concerns here:

  • what action to take at some later point in time
  • what object to perform that action on

Having a reference to an instance satisfies the second requirement. Pointers to member functions address the first: they are a very direct way to record - at one point in a program's execution - which action should be taken at some later stage of execution, possibly by another part of the program.

EXAMPLE

Say you have a monkey that can kiss people or tickle them. At 6pm, your program should set the monkey loose, and knows whom the monkey should visit, but around 3pm your user will type in which action should be taken.

A beginner's approach

So, at 3pm you could set a variable "enum Action { Kiss, Tickle } action;", then at 6pm you could do something like "if (action == Kiss) monkey->kiss(person); else monkey->tickle(person)".

Issues

But that introducing an extra level of encoding (the Action type's introduced to support this - built in types could be used but would be more error prone and less inherently meaningful). Then - after having worked out what action should be taken at 3pm, at 6pm you have to redundantly consult that encoded value to decide which action to take, which will require another if/else or switch upon the encoded value. It's all clumsy, verbose, slow and error prone.

Member function pointers

A better way is to use a more specialised varibale - a member function pointer - that directly records which action to perform at 6pm. That's what a member function pointer is. It's a kiss-or-tickle selector that's set earlier, creating a "state" for the monkey - is it a tickler or a kisser - which can be used later. The later code just invokes whatever function's been set without having to think about the possibilities or have any if/else-if or switch statements.

To invoke it, you need a reference to an instance, but then you can call the func direct & don't need a pointer to it.

Back to this. So, this is good if you make the decision about which action to take at compile time (i.e. a point X in your program, it'll definitely be a tickle). Function pointers are for when you're not sure, and want to decouple the setting of actions from the invocation of those actions.

Tony
+3  A: 

In my opinion, member function pointers do are not terribly useful to the average programmer in their raw form. OTOH, constructs like ::std::tr1::function that wrap member function pointers together with a pointer to the object they're supposed to operate on are extremely useful.

Of course ::std::tr1::function is very complex. So I will give you a simple example that you wouldn't actually use in practice if you had ::std::tr1::function available:

// Button.hpp
#include <memory>

class Button {
 public:
   Button(/* stuff */) : hdlr_(0), myhandler_(false) { }
   ~Button() {
      // stuff
      if (myhandler_) {
         delete hdlr_;
      }
   }
   class PressedHandler {
    public:
      virtual ~PressedHandler() = 0;

      virtual void buttonPushed(Button *button) = 0;
   };

   // ... lots of stuff

   // This stores a pointer to the handler, but will not manage the
   // storage.  You are responsible for making sure the handler stays
   // around as long as the Button object.
   void setHandler(const PressedHandler &hdlr) {
      hdlr_ = &hdlr;
      myhandler_ = false;
   }

   // This stores a pointer to an object that Button does not manage.  You
   // are responsible for making sure this object stays around until Button
   // goes away.
   template <class T>
   inline void setHandlerFunc(T &dest, void (T::*pushed)(Button *));

 private:
   const PressedHandler *hdlr_;
   bool myhandler_;

   template <class T>
   class PressedHandlerT : public Button::PressedHandler {
    public:
      typedef void (T::*hdlrfuncptr_t)(Button *);

      PressedHandlerT(T *ob, hdlrfuncptr_t hdlr) : ob_(ob), func_(hdlr) { }
      virtual ~PressedHandlerT() {}

      virtual void buttonPushed(Button *button) { (ob_->*func_)(button); }

    private:
      T * const ob_;
      const hdlrfuncptr_t func_;
   };
};

template <class T>
inline void Button::setHandlerFunc(T &dest, void (T::*pushed)(Button *))
{
   PressedHandler *newhandler = new PressedHandlerT<T>(&dest, pushed);
   if (myhandler_) {
      delete hdlr_;
   }
   hdlr_ = newhandler;
   myhandler_ = true;
}

// UseButton.cpp
#include "Button.hpp"
#include <memory>

class NoiseMaker {
 public:
   NoiseMaker();
   void squee(Button *b);
   void hiss(Button *b);
   void boo(Button *b);

 private:
   typedef ::std::auto_ptr<Button> buttonptr_t;
   const buttonptr_t squeebutton_, hissbutton_, boobutton_;
};


NoiseMaker::NoiseMaker()
     : squeebutton_(new Button), hissbutton_(new Button), boobutton_(new Button)
{
   squeebutton_->setHandlerFunc(*this, &NoiseMaker::squee);
   hissbutton_->setHandlerFunc(*this, &NoiseMaker::hiss);
   boobutton_->setHandlerFunc(*this, &NoiseMaker::boo);
}

Assuming Button is in a library and not alterable by you, I would enjoy seeing you implement that cleanly using a virtual base class without resorting to a switch or if else if construct somewhere.

Omnifarious
Your code actually gave some ideas to use in my play with X-dev. I'll definitely be looking at your code-sample some more.
slashmais
I wasn't aware of std::tr1 - thanx. Looks like there's a lot that can be done with it :)
slashmais
+4  A: 

Member functions, like many function pointers, act as callbacks. You could manage without them by creating some abstract class that calls your method, but this can be a lot of extra work.

One common use is algorithms. In std::for_each, we may want to call a member function of the class of each member of our collection. We also may want to call the member function of our own class on each member of the collection - the latter requires boost::bind to achieve, the former can be done with the STL mem_fun family of classes (if we don't have a collection of shared_ptr, in which case we need to boost::bind in this case too). We could also use a member function as a predicate in certain lookup or sort algorithms. (This removes our need to write a custom class that overloads operator() to call a member of our class, we just pass it in directly to boost::bind).

The other use, as I mentioned, are callbacks, often in event-driven code. When an operation has completed we want a method of our class called to handle the completion. This can often be wrapped into a boost::bind functor. In this case we have to be very careful to manage the lifetime of these objects correctly and their thread-safety (especially as it can be very hard to debug if something goes wrong). Still, it once again can save us from writing large amounts of "wrapper" code.

CashCow
+2  A: 

The whole point of pointers of pointer-to-member function type is that they act as a run-time way to reference a specific method. When you use the "usual" syntax for method access

object.method();
pointer->method();

the method part is a fixed, compile-time specification of the method you want to call. It is hardcoded into your program. It can never change. But by using a pointer of pointer-to-member function type you can replace that fixed part with a variable, changeable at run-time specification of the method.

To better illustrate this, let me make the following simple analogy. Let's say you have an array

int a[100];

You can access its elements with fixed compile-time index

a[5]; a[8]; a[23];

In this case the specific indices are hardcoded into your program. But you can also access array's elements with a run-time index - an integer variable i

a[i];

the value of i is not fixed, it can change at run-time, thus allowing you to select different elements of the array at run-time. That is very similar to what pointers of pointer-to-member function type let you do.

The question you are asking ("since you have the instance, why not call the member function directly") can be translated into this array context. You are basically asking: "Why do we need a variable index access a[i], when we have direct compile-time constant access like a[1] and a[3]?" I hope you know the answer to this question and realize the value of run-time selection of specific array element.

The same applies to pointers of pointer-to-member function type: they, again, let you to perform run-time selection of a specific class method.

AndreyT
+2  A: 

Member pointers + templates = pure win.

e.g. http://stackoverflow.com/questions/3964357/how-to-tell-if-class-contains-a-certain-member-function-in-compile-time/3964445#3964445

or

template<typename TContainer,
         typename TProperty,
         typename TElement = decltype(*Container().begin())>
TProperty grand_total(TContainer& items, TProperty (TElement::*property)() const)
{
   TProperty accum = 0;
   for( auto it = items.begin(), end = items.end(); it != end; ++it) {
       accum += (it->*property)();
   }
   return accum;
}

auto ship_count = grand_total(invoice->lineItems, &LineItem::get_quantity);
auto sub_total = grand_total(invoice->lineItems, &LineItem::get_extended_total);
auto sales_tax = grand_total(invoice->lineItems, &LineItem::calculate_tax);
Ben Voigt
This concept can be very useful.
slashmais