如果要从队列中读取数据,如何在C ++中设置/注册回调函数来调用函数?
修改1:
使用Neil的答案获得完整答案(在头文件中):
#include <vector.h>
class QueueListener {
public:
virtual void DataReady(class MyQueue *q) = 0;
virtual ~QueueListener() {}
};
class MyQueue {
public:
void Add (int x) {
theQueue.push_back(x);
for (int i = 0; i < theCallBacks.size(); i++) {
theCallBacks[i]->DataReady(this);
}
}
void Register (QueueListener *ql) {
theCallBacks.push_back(ql);
}
private:
vector <QueueListener *> theCallBacks;
vector <int> theQueue;
};
class MyListener : public QueueListener {
public:
virtual ~MyListener () {
printf("MyListener destructor!");
}
MyListener(MyQueue *q);
virtual void DataReady(class MyQueue *p);
};
注册:
#include "File1.h"
MyListener::MyListener(MyQueue *q)
{
q->Register(this);
}
void MyListener::DataReady(class MyQueue *p)
{
Sleep(500);
}
然后是电话:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
MyQueue *q = new MyQueue();
MyListener ml(q);
q->Add(1);
}
答案 0 :(得分:3)
概括地说,创建一个QueueListener基类:
class QueueListener {
public:
virtual void DataReady( class MyQueue & q ) = 0;
virtual ~QueueListener() {}
};
和一个队列类(以整数队列为例:
class MyQueue {
public:
void Add( int x ) {
theQueue.push_back( x );
for ( int i = 0; i < theCallBacks.size(); i++ ) {
theCallBacks[i]->DataReady( * this );
}
}
void Register( QueueListener * ql ) {
theCallBacks.push_back( ql );
}
private:
vector <QueueListener *> theCallBacks;
SomeQueueType <int> theQueue;
};
您派生了想要从QueueListener回调的类并实现DataReady函数。然后,使用队列实例注册派生类的实例。
答案 1 :(得分:3)
看看Boost.Signals。
从教程中窃取的示例:
struct HelloWorld
{
void operator()() const
{
std::cout << "Hello, World!" << std::endl;
}
};
// ...
// Signal with no arguments and a void return value
boost::signal<void ()> sig;
// Connect a HelloWorld slot
HelloWorld hello;
sig.connect(hello);
// Call all of the slots
sig();
答案 2 :(得分:2)
我喜欢boost.asio用于回调的方法。在ASIO中,它们被称为处理程序。请原谅我的c ++ 0x,它写得比c ++ 98快得多。
class MyQueue
{
//...
Register( const std::function<void()>& callback )
{
m_callbacks.push_back(callback);
}
Add( const int& i )
{
// ...
for( const auto& callback: m_callbacks )
{
callback();
}
}
std::vector<std::function<void()>> m_callbacks;
};
class SomeClass
{
public:
void SomeQueueIsReady( MyQueue& )
{ /* do something with MyQueue */ }
};
void register_callback()
{
SomeClass some;
MyQueue queue;
// using bind
queue.Register( std::bind( &SomeClass::SomeQueueIsReady, &some, std::ref(queue) ) );
// or using a lambda
queue.Register( [&queue,&some](){ some.SomeQueueIsReady( queue ); } );
}
关键点是回调是一个仿函数,因此用户不依赖于特定的类层次结构,并且回调不接受任何参数。如果您想要传入参数,请自行绑定它们。例外情况是,回调在注册回调时产生的信息不可用。一个例子可能是添加项目的时间。
没有什么能阻止你在c ++ 98中使用这个解决方案。你不能使用lamdbas,但是boost::function
和boost::bind
与它们的c ++ 0x计数器部分几乎相同。
请注意,您必须仔细管理对象的生命周期。无论是Neil还是我的解决方案都是如此。