繁体   English   中英

你如何传递成员函数指针?

[英]How do you pass a member function pointer?

我试图将类中的成员函数传递给一个带有成员函数类指针的函数。 我遇到的问题是我不确定如何使用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(...)包含在另一个类中,其中“object”是模板。

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

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

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

然后你可以使用两个指针来调用函数:

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

我强烈建议使用boost::bindboost::function来做这样的事情。

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

我知道这是一个相当古老的话题。 但是有一种优雅的方法可以用c ++ 11来处理这个问题

#include <functional>

像这样声明你的函数指针

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

声明你将这个东西传递给你的函数

void SetHandler(Max Handler);

假设您将正常函数传递给它,您可以像平常一样使用它

SetHandler(&some function);

假设你有一个成员函数

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

在您的代码中,您可以使用像这样的std::placeholders传递它

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

你是不是更好地使用标准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'方法。

在极少数情况下,您恰好使用Borland C ++ Builder开发并且不介意编写特定于该开发环境的代码(即,不能与其他C ++编译器一起使用的代码),您可以使用__closure关键字。 我发现了一篇关于C ++ Builder闭包小文章 它们主要用于Borland VCL。

其他人告诉你如何正确地做到这一点。 但我很惊讶没有人告诉你这个代码实际上是危险的:

this->ButtonFunc = &ButtonFunc;

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

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

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

因为ButtonObj是一个指向对象的指针

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM