Question

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.

Was it helpful?

Solution

To call a member function by pointer, you need two things: A pointer to the object 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;
}

OTHER TIPS

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

See Pass and call a member function (boost::bind / boost::function?)

I know this is a quite old topic. But there is an elegant way to handle this with c++11

#include <functional>

declare your function pointer like this

typedef std::function<int(int,int) > Max;

declare your the function your pass this thing into

void SetHandler(Max Handler);

suppose you pass a normal function to it you can use it like normal

SetHandler(&some function);

suppose you have a member function

class test{
public:
  int GetMax(int a, int b);
...
}

in your code you can pass it using std::placeholders like this

test t;
Max Handler = std::bind(&test::GetMax,&t,std::placeholders::_1,std::placeholders::_2);
some object.SetHandler(Handler);

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.

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.

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top