How do you pass a member function pointer?

谁说我不能喝 提交于 2019-11-26 02:03:35
Commodore Jaeger

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;
}
Matt Cruikshank

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

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

Yuanlong Li

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!