我正在尝试从另一个类中运行一个类的方法,我有一个基本的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 (*)()'
感谢您的建议。
答案 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)
sayHello应该是一个静态函数。
因为普通的成员函数有隐含的参数 - 这个。所以sayHello的完整签名是void sayHello(Foo* this);
另一种方式 - 使用pointer to class member。
您也可以使用仿函数结构而不是函数。