【问题标题】:How do you pass a member function pointer?你如何传递一个成员函数指针?
【发布时间】:2010-09-12 22:04:10
【问题描述】:

我试图将一个类中的成员函数传递给一个接受成员函数类指针的函数。我遇到的问题是我不确定如何使用 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;
}

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

【问题讨论】:

    标签: c++ class function pointers member


    【解决方案1】:

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

    【讨论】:

    • A pointer to the class - 应该是A pointer to the object吗?
    • 非常感谢。无法弄清楚语法类似于 ((ButtonObj)->*(ButtonFunc))()
    【解决方案2】:

    我强烈推荐boost::bindboost::function 来做类似的事情。

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

    【讨论】:

      【解决方案3】:

      我知道这是一个相当古老的话题。但是有一种优雅的方法可以用 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);
      

      【讨论】:

      • 谢谢。不过你有一个类型:它是std::placeholders,复数形式。
      【解决方案4】:

      使用标准 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”方法。

      【讨论】:

      • 问题在于,一个按钮可以调用的不同功能的数量之多,会使这项任务变得非常乏味。一个按钮可能调用的函数可能有 75 到 100 个。
      • 一个 testMenu hasA ButtonContract(或其中许多),而不是 isA 关系。这种方法很难实现具有相同操作的两个按钮或具有不同操作的按钮。
      【解决方案5】:

      如果您碰巧使用 Borland C++Builder 进行开发,并且不介意编写特定于该开发环境的代码(即不能与其他 C++ 编译器一起使用的代码),您可以使用__closure 关键字。我找到了small article about C++Builder closures。它们主要用于 Borland VCL。

      【讨论】:

      • 这是一个相当……晦涩难懂的解决方案。
      • 是的,它很模糊。 :) 不过,Delphi 和 C++Builder 遗留代码漂浮在公司领域。最好彻底。
      【解决方案6】:

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

      this->ButtonFunc = &ButtonFunc;
      

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

      我同意 Commodore 的解决方案。但是你得把他的台词改成

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-11-29
        • 2018-04-14
        • 2012-06-27
        • 2012-08-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多