C ++从类B中运行类A的函数指针作为回调

时间:2013-06-20 01:54:11

标签: c++ pointers callback

我正在尝试从另一个类中运行一个类的方法,我有一个基本的GUI,让用户填写他的名字和密码,当它点击登录按钮时,另一个接管并处理事件,我想要在成功登录的情况下设置回调,但是我在将函数指针发送到我的处理程序时遇到了问题。

我做了一个我想要做的事情的原始例子。

#include <iostream>

using namespace std;

class LoginHandler {
public:
    void loginAttempt(bool result)
    {
        if(result == true)
        {
            cout << "Login success! W00t!" << endl;

            //Run my callback :)
            callback();
        } else {
            cout << "Login failed." << endl;
        }
    }

    void setCallback(void (*cb)())
    {
        callback = cb;
    }

private:
    void (*callback)();
};

class Foo {
public:
    void run()
    {
        LoginHandler* loginHandler = new LoginHandler();
        loginHandler->setCallback(&Foo::sayHello);

        loginHandler->loginAttempt(false);
        loginHandler->loginAttempt(true);
    }

    void sayHello()
    {
        cout << "You actually logged in! Isn't that amazing!?" << endl;
    }
};

int main()
{
    Foo foo;
    foo.run();

    return 0;
}

我收到了下一个错误:

In member function 'void Foo::run()':
error: no matching function for call to 'LoginHandler::setCallback(void (Foo::*)())'
note: candidate is: void LoginHandler::setCallback(void (*)())
note:   no known conversion for argument 1 from 'void (Foo::*)()' to 'void (*)()'

感谢您的建议。

3 个答案:

答案 0 :(得分:1)

您已指定“setCallback”采用函数指针,而不是成员函数指针。

void setCallback(void (*cb)())

你正在调用它 - 正如编译器所抱怨的那样 - 使用成员函数指针

loginHandler->setCallback(&Foo::sayHello);

为了获取成员函数指针,setCallback定义必须能够确定要使用的类,并且调用回调的位置必须知道哪个类可以取消引用指针。

通常人们使用C风格的回调处理程序来解决这个问题,

static FooSayHelloCallback(void* fooParam)
{
    Foo* foo = static_cast<Foo*>(fooParam);
    foo->sayHello();
}

或仿函数对象

struct LoginHandlerCallbackFunctor
{
    void* m_this;
public:
    FooSayHelloFunctor(void* this_) : m_this(this_) {}
    virtual void operator()() = 0;
};

struct FooSayHelloFunctor : public LoginHandlerCallbackFunctor
{
public:
    FooSayHelloFunctor(Foo* foo_) : LoginHandlerCallbackFunctor(foo_) {}
    virtual void operator()() { ((Foo*)m_this)->sayHello(); }
};

然后

class LoginHandler {
    ...
    LoginHandlerCallbackFunctor m_callback;
    ...

    void setCallback(const LoginHandlerCallbackFunctor& functor)
    {
        m_callback = functor;
    }

    void doCallback()
    {
        m_callback(); // calls operator()
    }

如果你想真正想要你可以用模板做到这一点。

或者,您也可以使用C ++ 11 Lambdas和std :: function。

class LoginHandler
{
  typedef std::function<void(void)> GreetingCallback;

  GreetingCallback m_callback;
  ...
  void setCallback(const GreetingCallback& callback_)
  {
      m_callback = callback_;
  }

  void doCallback()
  {
      m_callback();
  }
}

和foo

LoginHandler loginHandler();
loginHandler.setCallback([=]() { sayHello(); });

loginHandler->loginAttempt(false);
loginHandler->loginAttempt(true);

答案 1 :(得分:1)

原始函数指针大多已经过时,只能用于低级别的性能关键内容。对于我们其他人来说,C ++有std::function这是无限好的。它可以轻松处理像你这样的案件。

如果由于没有C ++ 11编译器而无法使用它,boost::function是替代品。

答案 2 :(得分:0)

  1. sayHello应该是一个静态函数。 因为普通的成员函数有隐含的参数 - 这个。所以sayHello的完整签名是void sayHello(Foo* this);

  2. 另一种方式 - 使用pointer to class member

  3. 您也可以使用仿函数结构而不是函数。