How to add/design callback function

笑着哭i 提交于 2021-02-08 03:22:25

问题


How do I setup/register a callback function, in C++, to call a function when there is data to be read from a queue?

Edit 1:

Using Neil's answer for a complete answer (in header file):

#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);
};

And the registering:

#include "File1.h"


MyListener::MyListener(MyQueue *q)
{
   q->Register(this);
}

void MyListener::DataReady(class MyQueue *p)
{
   Sleep(500);
}

Then the calls:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    MyQueue *q = new MyQueue();
    MyListener ml(q);

    q->Add(1);

}

回答1:


In outline, create a QueueListener base class:

class QueueListener {
   public:
       virtual void DataReady( class MyQueue & q ) = 0;
       virtual ~QueueListener() {}
};

and a queue class (make this queue of integers as example:

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;

};

You derive the classes that want to be called back from QueueListener and implement the DataReady function. You then register instances of the derived class with your queue instance.




回答2:


Have a look at Boost.Signals.

Example stolen from tutorial:

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();



回答3:


I like the approach that boost.asio uses for callback. In ASIO they are referred to as handlers. Please excuse my c++0x, it is so much faster to write than 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 ); } );
}

The key points are the callback is a functor so the user isn't tied to a particular class hierarchy and the callbacks don't take any parameters. If you want parameters passed in, you bind them yourself. The exception is if the callback produces information not available when the callback was registered. An example could be the time when the item was added.

There is nothing stopping you from using this solution in c++98. You cannot use lamdbas, but boost::function and boost::bind are near identical to their c++0x counter parts.

Be aware that you'll have to manage object lifetimes carefully. That is the case with either Neil's or my solution.



来源:https://stackoverflow.com/questions/2721421/how-to-add-design-callback-function

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!