首页 > 解决方案 > 如何使用回调使工作简单的按钮类?

问题描述

如何制作简单的按钮类以在按下时调用自定义函数。一些代码示例:

class Button
{
    public:
        Button();
        Draw();
        Press();
        SetCallback(void(*cback)());

    priate:
        void (*callback)();
}

void Button::SetCallback(void(*cback)())
{
    callback = cback;
}

class GameState
{
    ...
}

class MenuState : public GameState
{
    Button *btn;
}

class Game
{
    ...
}
bool Game::Init()
{
    std::unique_ptr<GameState> menu = std::unique_ptr<MenuState>(new MenuState);

}
void Game::PopState(){
        states.pop_back();
}

在此示例中,如何将按钮中的回调设置为 Game::PopState() 函数。我需要然后我按下按钮调用 Game::PopState 函数。

标签: c++button

解决方案


您正在寻找的是关于函数指针的教程,可以在此处找到。

如果您需要传递一个参数,您的按钮函数指针应该有一个指针或对您的 Game 对象的引用,因为成员函数需要引用(对哪个对象拥有函数调用)。如果您的 Game 类中的 popstate 函数是私有的,您可能需要将其设为公开或友元函数。

您应该能够通过将字符串引用替换为对 Game 对象的引用来修改下面的示例。如果您需要更通用的回调,请查看模板(更好但更复杂)或类型双关语(通常被认为是不好的做法


#include <iostream>
#include <string>
class Button
{
    public:
        void SetCallback(void(*cback)(std::string&));
        void Press(std::string str){
          //Make sure some sort of check is done in order to prevent undefined behavior from a call
          if(callback != nullptr)
            callback(str);
        }
        Button(){
          callback = nullptr;
        }
    private:
        void (*callback)(std::string&);
};

void Button::SetCallback(void(*cback)(std::string&))
{
    callback = cback;
}
//Method 2 for calling function
void DoStuff(std::string& str){
  std::cout << str;
}

int main(void){

  Button btn;
  //Method 1 for calling function, replace body with Game.PopStates();
  auto foo = [](std::string& str){ std::cout<<str.size();};
  btn.SetCallback(foo);
  btn.Press("A");
  //Method 2 for calling function
  btn.SetCallback(&DoStuff);
  btn.Press("\nPressed Button");
  return 0;
}

你的 Game 函数指针应该是这样的:

void SetCallback(void(*cback)(Game&));

你可以这样称呼它:

auto foo = [](Game& g){ g.DoStuffInClass(); };
  btn.SetCallback(foo);
  btn.Press(game);

上面的示例工作正常,通常是您需要做的所有事情,但本文更深入地介绍了成员函数指针这篇文章的主要内容是 typedef 是另一种编写成员函数指针的方法,如下所示:

typedef int (Fred::*FredMemFn)(char x, float y); // 请这样做!

但是,上述所有操作(当使用 PopStates 实现时)会将您的按钮回调锁定为使用您的 Game 对象调用的 void 函数,这会限制您使用按钮的能力。如果您希望允许在没有 Game 对象的情况下执行特殊情况,则可以使用指针而不是引用,但无论哪种方式,您的 Game 对象都必须找到某种方式放入回调中。


推荐阅读