如何传递成员函数指针?

时间:2020-03-06 14:41:34  来源:igfitidea点击:

我试图将类中的成员函数传递给采用成员函数类指针的函数。我遇到的问题是我不确定如何使用this指针在类中正确执行此操作。有人有建议吗?

这是传递成员函数的类的副本:

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

函数x.SetButton(...)包含在另一个类中,其中"对象"是模板。

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

如果有人对如何正确发送此功能有任何建议,以便以后使用。

解决方案

我强烈建议boost :: bindboost :: function这样的东西。

请参阅传递并调用成员函数(boost :: bind / boost :: function?)

在我们碰巧使用Borland C ++ Builder进行开发并且不介意编写特定于该开发环境的代码(即,与其他C ++编译器不兼容的代码)的情况很少,可以使用__closure关键字。我找到了一篇有关C ++ Builder闭包的小文章。它们主要用于Borland VCL。

要通过指针调用成员函数,我们需要做两件事:指向对象的指针和指向函数的指针。在MenuMenu :: 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;
}

然后,我们可以使用两个指针来调用该函数:

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

不要忘记将指向我们对象的指针传递给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;
}

使用标准OO会更好吗?定义一个合同(虚拟类)并在我们自己的类中实现它,然后将引用传递给我们自己的类,然后让接收方调用合同函数。

使用示例(我将" test2"方法重命名为" 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;
    }
};

在接收器方法中,存储对ButtonContract的引用,然后在要执行按钮的动作时,只需调用该存储的ButtonContract对象的'buttonAction'方法即可。

其他人告诉过我们如何正确执行操作。但令我惊讶的是,没有人告诉我们此代码实际上很危险:

this->ButtonFunc = &ButtonFunc;

因为ButtonFunc是一个参数,所以当函数返回时它将超出范围。我们正在使用它的地址。我们将得到一个类型为void(object :: ** ButtonFunc)()的值(指向成员函数指针的指针),并将其分配给this-> ButtonFunc。在我们尝试使用this-> ButtonFunc时,我们将尝试访问(现在不再存在)本地参数的存储,程序可能会崩溃。

我同意Commodore的解决方案。但是你必须改变他的路线

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

因为ButtonObj是指向对象的指针。