views:

2273

answers:

6

I am trying to pass a member function within a class to a function that takes a member function class pointer. The problem I am having is that I am not sure how to properly do this within the class using the this pointer. Does anyone have suggestions?

Here is a copy of the class that is passing the member function:

class testMenu : public MenuScreen{
public:

bool draw;

MenuButton<testMenu> x;

testMenu():MenuScreen("testMenu"){
 x.SetButton(100,100,TEXT("buttonNormal.png"),TEXT("buttonHover.png"),TEXT("buttonPressed.png"),100,40,&this->test2);

 draw = false;
}

void test2(){
 draw = true;
}
};

The function x.SetButton(...) is contained in another class, where "object" is a template.

void SetButton(int xPos, int yPos, LPCWSTR normalFilePath, LPCWSTR hoverFilePath, LPCWSTR pressedFilePath, int Width, int Height, void (object::*ButtonFunc)()) {

 BUTTON::SetButton(xPos, yPos, normalFilePath, hoverFilePath, pressedFilePath, Width, Height);

 this->ButtonFunc = &ButtonFunc;
}

If anyone has any advice on how I can properly send this function so that I can use it later.

+7  A: 

There is a section on the subject in the C++ FAQ.

moonshadow
+11  A: 

I'd strongly recommend boost::bind and boost::function for anything like this.

Matt Cruikshank
A: 

In the rare case that you happen to be developing with Borland C++Builder and don't mind writing code specific to that development environment (that is, code that won't work with other C++ compilers), you can use the __closure keyword. I found a small article about C++Builder closures. They're intended primarily for use with Borland VCL.

Parappa
That's a rather... obscure solution.
Josh Matthews
Yup, it's obscure. :) There's Delphi and C++Builder legacy code floating out there in corporate land, though. Best to be thorough.
Parappa
+7  A: 

To call a member function by pointer, you need two things: A pointer to the class and a pointer to the function. You need both in MenuButton::SetButton()

template <class object>
void MenuButton::SetButton(int xPos, int yPos, LPCWSTR normalFilePath,
        LPCWSTR hoverFilePath, LPCWSTR pressedFilePath,
        int Width, int Height, object *ButtonObj, void (object::*ButtonFunc)())
{
  BUTTON::SetButton(xPos, yPos, normalFilePath, hoverFilePath, pressedFilePath, Width, Height);

  this->ButtonObj = ButtonObj;
  this->ButtonFunc = ButtonFunc;
}

Then you can invoke the function using both pointers:

((ButtonObj).*(ButtonFunc))();

Don't forget to pass the pointer to your object to MenuButton::SetButton():

testMenu::testMenu()
  :MenuScreen("testMenu")
{
  x.SetButton(100,100,TEXT("buttonNormal.png"), TEXT("buttonHover.png"),
        TEXT("buttonPressed.png"), 100, 40, this, test2);
  draw = false;
}
Commodore Jaeger
A: 

Would you not be better served to use standard OO. Define a contract (virtual class) and implement that in your own class, then just pass a reference to your own class and let the receiver call the contract function.

Using your example (I've renamed the 'test2' method to 'buttonAction'):

class ButtonContract
{
  public:
    virtual void buttonAction();
}


class testMenu : public MenuScreen, public virtual ButtonContract
{
  public:
    bool draw;
    MenuButton<testMenu> x;

    testMenu():MenuScreen("testMenu")
    {
      x.SetButton(100,100,TEXT("buttonNormal.png"), 
              TEXT("buttonHover.png"), 
              TEXT("buttonPressed.png"), 
              100, 40, &this);
      draw = false;
    }

    //Implementation of the ButtonContract method!
    void buttonAction()
    {
      draw = true;
    }
};

In the receiver method, you store the reference to a ButtonContract, then when you want to perform the button's action just call the 'buttonAction' method of that stored ButtonContract object.

GKelly
The problem is that the sheer number of different functions that can be called by a button, would make this task very tedious. There are probably 75 to 100 functions that a button can possibly call.
Matt Pascoe
+1  A: 

Others have told you how to do it correctly. But I'm surprised no-one told you this code is actually dangerous:

this->ButtonFunc = &ButtonFunc;

Since ButtonFunc is a parameter, it will go out of scope when the function returns. You are taking its address. You will get a value of type void (object::**ButtonFunc)() (pointer to a pointer to a member function) and assign it to this->ButtonFunc. At the time you would try to use this->ButtonFunc you would try to access the storage of the (now not existing anymore) local parameter, and your program would probably crash.

I agree with Commodore's solution. But you have to change his line to

((ButtonObj)->*(ButtonFunc))();

since ButtonObj is a pointer to object.

Johannes Schaub - litb