Non-Static Member Function Pointers!

Started by
7 comments, last by nhold 13 years, 11 months ago
Hey all! First of all the error I am having: error C2064: term does not evaluate to a function taking 0 arguments So, basically what I am trying to do is implement a Button class, which can be given a function(pointer!) through it's constructor which it then uses when it is 'activated'. Here is basic code showing what I have: Button


class GameManager; // Pre-declare of game manager.

class Button
{
public:
    Button(void (GameManager::*aFunctionPointer)(void)); // Takes a function pointer and assigns it to mFunctionPointer

    void Activate(); // This just calls mFunctionPointer (like: mFunctionPointer();) 
private:
protected:
    void (GameManager::*mFunctionPointer)(void);
}

GameManager

#include "button.h"

class GameManager
{
public:
void testfunction(void)
{
    // writes to my log output.
}

 GameManger()
{
     mTestButton = new Button(GameManager::testfunction);
}
private:
Button *mTestButton;

protected:
   
}

I did a search on here, and found that boost lib was heavily recommended :(. I kind of feel like not installing and using boost JUST for this. I also removed the parenthises on the end of: mFunctionPointer(); when it was called in Activate, so it looked like this: mFunctionPointer That worked and when I ran in debug, it showed the correct function being pointed to (but obviously didn't call it). Now I believe I know the problem, but not the solution. It wants something like(?): (aGameManager.*mFunctionPointer)(); However button doesn't know about GameManager (besides the pre-declare) I can't have it as an argument for Activate, and I can't copy a GameManager (Via passing into a function argument). Hopefully this wasn't too long-winded, thanks for any help! So what to do?

Engineering Manager at Deloitte Australia

Advertisement
Take a look at this, it's a good place to start when having issues with pointers to member functions: C++ FAQ Lite - Pointers to member functions

[edit]
From what your describing, you do probably need some kind of functor implemented, since pointers to member functions can be a little tricky. You need an instance of the class to make them work, and a functor helps alleviate some of the problems.

You don't necessarily need to use boost (which I would recommend), but your going to probably need some kind of functor implementation.

"I can't believe I'm defending logic to a turing machine." - Kent Woolworth [Other Space]

Pass it a reference to the GameManager you want to use the member function pointer on.
First of all, I suggest that any time you use member function pointers, you use a typedef to make your life easier:

public:    typedef void (GameManager::*Callback)(void);


I think what you're looking for, if you really want the callback to be a member of GameManager, is dependency injection. Add a reference member to your Button:

private:    const GameManager& mManager;


And set it with your constructor:

public:    Button(const GameManager& gm, Callback fn) :        mManager(gm), mFunctionPointer(fn) { ... }


Button is only manipulating a GameManager&, so Button.cpp does not even need to #include "GameManager.h" unless you make use of specific functions from GameManager. You can then invoke the function as usual:

    mManager.*mFunctionPointer();


Hope this helps!

Edit: Beaten by seconds. :P
Quote:Original post by CRYP7IK
when it was called in Activate, so it looked like this:

mFunctionPointer

That worked and when I ran in debug, it showed the correct function being pointed to (but obviously didn't call it).

Sure, but ask yourself this: if the compiler allowed you to call mFunctionPointer in the way you're attempting to do, what should the "this" pointer be inside that call?

A (non-static) member function needs an instance of the class to which it belongs in order to operate. It needs a "this".

The (rather ugly) syntax used to call a member function pointer reflects this:

(obj.*memFuncPtr)(arg1, arg2, arg3);


To actually provide a solution to your problem, have a look at the "function" and "bind" libraries provided by boost. They're a really powerful combination.
Quote:Original post by Rattrap
Take a look at this, it's a good place to start when having issues with pointers to member functions: C++ FAQ Lite - Pointers to member functions

[edit]
From what your describing, you do probably need some kind of functor implemented, since pointers to member functions can be a little tricky. You need an instance of the class to make them work, and a functor helps alleviate some of the problems.

You don't necessarily need to use boost (which I would recommend), but your going to probably need some kind of functor implementation.


Thanks for the link. But I don't think I would like to create my own functor implementation, would rather use boost!

Quote:Original post by nullsquared
Pass it a reference to the GameManager you want to use the member function pointer on.


Okay, I tried (my interpretation of) this, it calls the function correctly and everything but I am unable to see member variables. I am giving the button a 'this' keyword in the gamemanager constructor.

Quote:Original post by EvincarOfAutumn
First of all, I suggest that any time you use member function pointers, you use a typedef to make your life easier:

*** Source Snippet Removed ***

I think what you're looking for, if you really want the callback to be a member of GameManager, is dependency injection. Add a reference member to your Button:

*** Source Snippet Removed ***

And set it with your constructor:

*** Source Snippet Removed ***

Button is only manipulating a GameManager&, so Button.cpp does not even need to #include "GameManager.h" unless you make use of specific functions from GameManager. You can then invoke the function as usual:

*** Source Snippet Removed ***

Hope this helps!

Edit: Beaten by seconds. :P


Yeah, I also tried this, however it says:

error C2758: 'Button::mGameManager' : must be initialized in constructor base/member initializer list

This may be due to me trying to create the button in the constructor of the GameManager and using *this for the reference to my GameManager instance.

Quote:Original post by the_edd
Quote:Original post by CRYP7IK
when it was called in Activate, so it looked like this:

mFunctionPointer

That worked and when I ran in debug, it showed the correct function being pointed to (but obviously didn't call it).

Sure, but ask yourself this: if the compiler allowed you to call mFunctionPointer in the way you're attempting to do, what should the "this" pointer be inside that call?

A (non-static) member function needs an instance of the class to which it belongs in order to operate. It needs a "this".

The (rather ugly) syntax used to call a member function pointer reflects this:

(obj.*memFuncPtr)(arg1, arg2, arg3);


To actually provide a solution to your problem, have a look at the "function" and "bind" libraries provided by boost. They're a really powerful combination.



Yeah, I came to the conclusion that something like:

(obj.*memFuncPtr)(arg1, arg2, arg3);


was needed, however I couldn't think of a good way to do this unless I made a GUIManager, which I think I am going to have to do.

:(


Maybe it would be better if I told you what I am trying to accomplish so we can have a discussion on how I could do it better.

So basically I want to have buttons in my menu and in game, where the menu buttons will change the game state, and the in game ones will create a spell (e.g. SpellManager.CreateSpell("Fireball")). However I don't want to have to have a class which inherits from a base class to do this otherwise I'll end up with hundreds of classes just for buttons!

Thanks for the help so far!


Engineering Manager at Deloitte Australia

Quote:Original post by CRYP7IK
So basically I want to have buttons in my menu and in game, where the menu buttons will change the game state, and the in game ones will create a spell (e.g. SpellManager.CreateSpell("Fireball")). However I don't want to have to have a class which inherits from a base class to do this otherwise I'll end up with hundreds of classes just for buttons!


Yep, you'll definitely want to look in to the function and bind libraries of boost, and possibly signals2, too.

EDIT: I should probably post some example code on how to use these things for your purposes.

// untestedusing boost::signals2::signal;using boost::bind;using boost::ref;struct Button{    // a signal that calls functions with no arguments and returns nothing    signal<void ()> on_click;         };// ...GameManager game_manager;Button button;void some_other_test_function(const std::string &s, double d){    // ...}// the use of ref() here is to avoid copying the GameManager.button.on_click.connect(bind(&GameManager::testfunction, ref(game_manager)));button.on_click.connect(bind(&some_other_test_function, "hello", 3.14));// fire our signalbutton.on_click(); // that called game_manager.testfunction() and// some_other_test_function("hello", 3.14)


Things to note:
1. you're not restricted to member functions of a particular class
2. in fact you're not restricted to member functions at all. Regular functions are also fair game, as are objects of classes with an operator().
3. the button and the actions you can have a button perform are entirely decoupled.
4. by using boost::bind, you don't have to implement some kind of abstract interface for every different concrete action you might want to associate with a button click.

[Edited by - the_edd on May 1, 2010 5:46:11 AM]
I don't have Boost installed, so I solved the problem like this:

template<typename pType,typename retType>class FunctorBase{public:	virtual retType call(pType)=0;};template<class OType,typename pType,typename retType>class Functor : public FunctorBase<pType,retType>{public:	Functor(OType* objInst,retType (OType::*objFunc)(pType param))		:objInst(objInst),objFunc(objFunc) {}	retType call(pType param){		return (*objInst.*objFunc)(param);	}private:	OType* objInst;	retType (OType::*objFunc)(pType);};


It's probably not the best solution, but it works.

Say you have a PopupMenu class, which you want to notify a ButtonEventHandler every time a button is clicked. The PopupMenu doesn't need to know which object it will be notifying, or the type of that object.
PopupMenu has a FunctorBase<pType,retType> member, where pType is the type of the parameter in the function call, and retType is the type the function returns.
Somewhere in your program (probably in the EventHandler), you store a Functor<OType,pType,retType> object. Since the EventHandler object is being called, OType = EventHandler.
The functor in EventHandler is constructed like this:
popupMenuFn(this,&EventHandler::PopupMenuButtonClicked), where the object instance is just the this pointer, and the name of the method being called is PopupMenuButtonClicked
The PopupMenu object receives a pointer to this functor in it's constructor, and when it wants to make a function call, it just calls functorPointer->call(parameter);
Quote:Original post by the_edd
...


Thanks, if I can't get this working in a simpler solution i'll have to use boost.

Quote:Original post by taz0010
...


I will definatly try and implement this before using boost. Looks a bit easier than I thought.

Thanks all, if I have any more trouble i'll post back here.

Engineering Manager at Deloitte Australia

This topic is closed to new replies.

Advertisement