【问题标题】:C++ Running a function pointer of class A from within class B as callbackC ++从类B中运行类A的函数指针作为回调
【发布时间】:2013-06-20 01:54:10
【问题描述】:

我正在尝试从另一个类中运行一个类的方法,我有一个基本的 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 (*)()'

感谢您的建议。

【问题讨论】:

    标签: c++ pointers callback


    【解决方案1】:

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

    如果您因为没有 C++11 编译器而无法使用它,boost::function 是一个直接替代品。

    【讨论】:

      【解决方案2】:

      您已指定“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 Lambda 和 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);
      

      【讨论】:

        【解决方案3】:
        1. sayHello 应该是一个静态函数。 因为普通的成员函数有隐式参数“this”。所以sayHello的完整签名是void sayHello(Foo* this);

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

        3. 您也可以使用函子结构代替函数。

        【讨论】:

        • 我将调用而不是 sayHello 的函数是一个相当大的函数,它会设置一个 3D 引擎并加载大量的东西,所以我不能真正让它成为静态的。但我会尝试您建议的其他 2 种方法。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-09-07
        • 2020-11-09
        • 2011-09-14
        • 2017-04-19
        • 1970-01-01
        • 2012-02-07
        • 1970-01-01
        相关资源
        最近更新 更多