2

我对 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 类中声明的枚举,因为函数指针不需要参数。我尝试过调整它,但没有成功。

关于我应该如何做的任何建议?

4

3 回答 3

0

Tha 库有一个设计错误。

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

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

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

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

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

如果不更改类,您想要做的就是不可能的,Button除非您使用一些糟糕的 hack,就像您在此处看到的那样,它试图std::bind使用裸函数指针在 C 中进行模拟。

于 2013-10-04T06:15:33.750 回答
0

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

为此,我建议您查看std::functionand 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));
于 2013-10-04T05:55:43.870 回答
0

对于回调, 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。

于 2013-10-04T05:57:28.277 回答