【问题标题】:Passing states of StateMachine as parameter to a function pointer C++ OOP将 StateMachine 的状态作为参数传递给函数指针 C++ OOP
【发布时间】:2013-10-04 05:48:08
【问题描述】:

我对 C++ 中函数指针的概念相当陌生,所以我不知道如何正确编写我的问题。请多多包涵。

基本上,我要做的是创建一个 Button 对象,其构造函数接受一个函数指针作为其参数。该函数指针指向一个将改变 StateMachine 状态的函数。

这是示例代码(它不起作用,并且不相关的部分已被剥离)

按钮.h

#include "StateMachine.h"

class Button
{
private:   
    void (*m_onclickAction)();    //a data member
public:
    Button(void (*action)());
};

StateMachine.h(不是我写的,我是有权限才用的。所以代码应该没有问题,我也不想修改)

#include <map>

template<class E, class T>
class StateMachine
{
public:
    typedef void (T::*CallbackOnInitialise)();
    typedef void (T::*CallbackOnExit)();
private:    
    T* m_pOwner;
    E m_currentState;

    // Maps to store function pointers to state functions.
    std::map<E, CallbackOnInitialise> m_statesOnInitialise;
    std::map<E, CallbackOnExit> m_statesOnExit;

public:
    StateMachine(T* pOwner, E emptyState)
    {
        m_currentState = emptyState;
        m_pOwner = pOwner;
    }

    void ChangeState(E statenext)
    {
        //do something to change the state
    }
};

所以在我的主程序类中,我可以做这样的事情

#include "Button.h"
#include "StateMachine.h"

//Code to instantiate an StateMachine object goes here
Button* aButton = new Button(aStateMachine->ChangeState(NEW_STATE));

问题是我想不出一种正确传递 NEW_STATE 的方法,它是在 Program 类中声明的枚举,因为函数指针不需要参数。我尝试过调整它,但没有成功。

对我应该如何做有什么建议吗?

【问题讨论】:

    标签: c++ oop function-pointers state-machine


    【解决方案1】:

    这里有几个问题。第一个是在您的版本中,您在创建Button 实例时调用 ChangeState 成员函数。二是m_onclickAction是指向函数的指针,与指向成员函数的指针不一样。

    为此,我建议您查看std::function 和std::bind:

    class Button
    {
        std::function<void(int)> m_onclickAction;
    
    public:
        Button(std::function<void(int)> action) { ... }
    };
    

    然后你可以像这样创建你的按钮:

    Button* aButton = new Button(
        std::bind(&StateMachine::ChangeState, aStateMachine, NEW_STATE));
    

    【讨论】:

      【解决方案2】:

      对于回调, boost::bind() 和 boost::function() 是一个非常有用的工具。所以你的 Button 类可能看起来像这样:

      class Button
      {
      public:
          typedef boost::function<void()> Callback;
          Button( Callback clickAction );
      private:   
          Callback m_onclickAction;    //a data member
      };
      

      使用参数传递 StateMachine 方法的代码是:

      Button* aButton = new Button( boost::bind( &StateMachine::ChangeState, aStateMachine, NEW_STATE ) );
      

      如果您使用 C++11,您可以将 boost::bind 替换为 std::bind 并将 boost::function 替换为 std::function。

      【讨论】:

        【解决方案3】:

        这个库有一个设计错误。

        问题在于函数指针只是 C++ 中的函数指针(不是闭包),因此它没有任何上下文。

        如果你想创建一个绘制蓝色圆圈的按钮,你需要一个全局函数来绘制一个不带参数的蓝色圆圈。

        如果您想要另一个按钮来绘制黄色圆圈,您将需要另一个全局函数来绘制一个不带参数的黄色圆圈。

        更具体地说,问题是该库没有任何方法可以在按钮中存储所谓的“上下文”,以便能够向您的代码传递用于绘制圆圈的颜色。

        C++11 添加了一些提醒闭包的东西(不是真正的东西,因为生命周期问题在没有垃圾收集的情况下很难用任何语言解决),但它们不是裸函数指针。

        如果不更改 Button 类,您想要做的就是不可能的,除非您使用一些糟糕的 hack,如 the one you can see here,它试图使用裸函数指针在 C 中模拟 std::bind。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-11-23
          • 2013-01-25
          • 2019-08-17
          • 1970-01-01
          • 2015-03-17
          • 2013-04-28
          相关资源
          最近更新 更多