How to add / design a callback function

How to set up / register a C ++ callback function to call a function when reading data from a queue?

Edit 1:

Using Neil's answer for a complete answer (in a 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 registration:

#include "File1.h"


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

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

      

Then calls:

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

    q->Add(1);

}

      

+2


a source to share


3 answers


In the outline, create a base QueueListener class:

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

      

and the class of the queue (take this queue of integers as an 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 get classes to be called back from the QueueListener and implement the DataReady function. Then you register instances of the derived class with a queue instance.

+3


a source


Take a look at Boost.Signals.

Example stolen from the 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


a source


I like the approach that boost.asio uses for the callback. In ASIO they are called handlers. Sorry my C ++ 0x, this is 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 ); } );
}

      

Key points: The callback is a functor, so the user is not tied to a specific class hierarchy, and the callbacks do not take any parameters. If you want the parameters to pass, you link them yourself. An exception is if the callback generates information not available when registering the callback. An example would be the time when the item was added.

Nothing prevents you from using this solution in C ++ 98. You can not use lamdbas, but boost::function

and boost::bind

are close to their countable parts of C ++ 0x.

Keep in mind that you need to carefully manage the lifespan of the object. This is the case neither with Neal nor with my decision.

+2


a source







All Articles