Go4Expert

Go4Expert (http://www.go4expert.com/)
-   C++ (http://www.go4expert.com/articles/cpp-tutorials/)
-   -   Callback Implementation using Static Function, Member Function and Functor in C++ (http://www.go4expert.com/articles/callback-implementation-using-static-t19120/)

Mridula 21Aug2009 17:15

Callback Implementation using Static Function, Member Function and Functor in C++
 

Introduction



This article explains about Callbacks and implmentation of it using below 3 different methods:
  1. Static Functions
  2. Non-Static or Member Functions
  3. Functor or Function Objects.

Background



About CallBack

It is an executable code, that is passed as an argument to other independent block of code or function to perform the required task. Here, it separates the callee from caller. Caller only needs to know the prototype of that function that would be used as a callback. So callbacks provide a mechanism where-in independently developed objects can be connected together, to meet the requirement.

It's Usage

1. Mostly, these callbacks are written in a common/generic library, so the applications can make use of them on needed basis - like "compare function" that acts as a callback and can be used in searching, sorting objects in a list or container.

2. If you want to terminate the application because of some trap, then to make sure of things that needs to be taken care before terminating the application, for that the application would register itself to a common callback utility that may be called as "cleanup".

3. Callbacks are also used in event handling in Finite State Machines or FSM. Wherein callback functions are used to perform set of things, on receiving an event and before changing to next state.

Lets take one problem/requirement to illustrate the implementation of callbacks using the above mentioned 3 different methods

The requirement is to find the Employee with given empId in the container. So the function for finding the Employee in the container uses the callback function or functor, for comparing the given empId with the empId of all the employee objects stored in the container and send the appropriate result.

Classes involed are:

class CallBackEmpInterface - Is a Base class contains empId_m.

class CallBackEmployee - Is a Employee class derives from CallBackEmpInterface class

class CallBackEmpContainer - Contains objects of class CallBackEmplyee


Implementation of Callback using Static or Member function of class object

Here Static function acts as a callback, whose function pointer is sent as a argument to the application which is going to make use of that specific callback later in it's computation.

The code


Code: Cpp

#include<iostream.h>

class CallBackEmpInterface
{
    unsigned int empId_m;

  public:

    CallBackEmpInterface()
    {
      cout<<"Ctor ::CallBackEmpInterface::default\n";
    }
   
    CallBackEmpInterface(unsigned int empId):empId_m(empId)
    {
      cout<<"Ctor ::CallBackEmpInterface\n";
    }
   
    unsigned int
    empId()
    {
      return (empId_m);
    }
   
    static bool compareEmpId(CallBackEmpInterface* obj1,
                          CallBackEmpInterface* obj2)
    {
      cout<<"\n\nCalling static function - CallBackEmpInterface::compareEmpId \n";
     
      if(obj1->empId() == obj2->empId())
      {
        return(0); //---
      }
      else if(obj1->empId() < obj2->empId())
      {
        return(-1); //---
      }
      else
      {
        return(1); //---
      }
    }
};

class CallBackEmployee : public CallBackEmpInterface
{
  public:

    CallBackEmployee(unsigned int empId):CallBackEmpInterface(empId)
    {
      cout<<"Ctor ::CallBackEmployee\n";
    }
};

class CallBackEmpContainer
{
  public:

    CallBackEmpContainer(): basePtr_mpp(NULL)
    {
      basePtr_mpp = new (CallBackEmpInterface *)[2];
    }

    void insert(const CallBackEmpInterface *obj_p)
    {
      CallBackEmpInterface *tempObj_p;
      tempObj_p = (CallBackEmpInterface *)obj_p;
     
      if(count !=2)
      {
        basePtr_mpp[count] = tempObj_p;
        ++count;
      }
    }

    void find(CallBackEmpInterface *critObj_p, bool (*compFun_p)(CallBackEmpInterface* obj1, CallBackEmpInterface* obj2))
    {
      unsigned int i;

      for(i=0; i<2; ++i)
      {
        // here calling the calling back function compareEmpId to find the result
        if(0 == (compFun_p(basePtr_mpp[i], critObj_p)))
        {
          cout<<"Found the object with empId as "<<critObj_p->empId()<<"...\n\n" ;
          return;
        }
      }
      cout<<"The container does not have this empId...\n\n";
    }
   
   
  private:

    CallBackEmpInterface ** basePtr_mpp;
    static unsigned int count;
};

unsigned int CallBackEmpContainer::count = 0;

int main()
{
  cout<<"Implementation of Callback Function using Static Function ...\n";
  cout<<"----------------------------------------------------------------\n\n";

  CallBackEmployee *obj1 = new CallBackEmployee(1);
  CallBackEmployee *obj2 = new CallBackEmployee(2);
 
  CallBackEmpContainer cb;
  cb.insert(obj1);
  cb.insert(obj2);
 
  //Create the criterian, to find a object with empId as "1" in the container
  CallBackEmployee *obj3 = new CallBackEmployee(1);

  //Find the object of type criterian obj3 in the container and send the results
  cb.find(obj3, CallBackEmpInterface::compareEmpId);

  delete (obj1);
  delete (obj2);
  delete (obj3);

  return(0);
}

Output:
--------------

Implementation of Callback Function using Static Function ...
----------------------------------------------------------------------

Ctor ::CallBackEmpInterface
Ctor ::CallBackEmployee
Ctor ::CallBackEmpInterface
Ctor ::CallBackEmployee
Ctor ::CallBackEmpInterface
Ctor ::CallBackEmployee


Calling static function - CallBackEmpInterface::compareEmpId
Found the object with empId as 1...


Here in this example, the static function compateEmpId is a comparision function, acts as a callback, whose function pointer is sent as an argument to find function. Where-as this find function is used by the main function for searching the Employee with specific empId in the container.

Implementation of Callback using Non-Static or Member function

Since pointer to member or non-static functions of a class object need the this pointer as well, it differs from the signature of the ordinary function pointers. But using the below work around, we can still make a callback to a member function.

A. Write a Static function as a Wrapper to a member function (which acts as a callback) providing the below arguments as -
  1. void pointer - which can be used to cast to the pointer to the object, whose member function can be invoked as a callback.
  2. Required parameters to call back function.
B. Call the member function using the cast ed pointer, by sending all the required parameters from this static function.

C. Then send the pointer to this Static Function as a argument to the function or application, where-in the callback function can be used in it's computation.

The code


Code: Cpp

#include<iostream.h>

class CallBackEmpInterface
{
    unsigned int empId_m;

  public:

    CallBackEmpInterface()
    {
      cout<<"Ctor ::CallBackEmpInterface::default\n";
    }
   
    CallBackEmpInterface(unsigned int empId):empId_m(empId)
    {
      cout<<"Ctor ::CallBackEmpInterface\n";
    }
   
    unsigned int
    empId()
    {
      return (empId_m);
    }
   
    bool compareEmpId(CallBackEmpInterface* obj1,
                      CallBackEmpInterface* obj2)
    {
      cout<<"\n\nCalling member function CallBackEmpInterface::compareEmpId \n";
     
      if(obj1->empId() == obj2->empId())
      {
        return(0); //---
      }
      else if(obj1->empId() < obj2->empId())
      {
        return(-1); //---
      }
      else
      {
        return(1); //---
      }
    }

    static bool wrapperToCompareEmpId(void* thisPtr, CallBackEmpInterface* obj1);
};

bool CallBackEmpInterface::wrapperToCompareEmpId(void * thisPtr, CallBackEmpInterface *obj1)
{
  cout<<"\n\nCallBackEmpInterface::wrapperToCompareEmpId\n";
  CallBackEmpInterface *myObj = (CallBackEmpInterface *)thisPtr;
  return (myObj->compareEmpId(myObj, obj1));
}

class CallBackEmployee : public CallBackEmpInterface
{
  public:

    CallBackEmployee(unsigned int empId):CallBackEmpInterface(empId)
    {
      cout<<"Ctor ::CallBackEmployee\n";
    }
};

class CallBackEmpContainer
{
  public:

    CallBackEmpContainer(): basePtr_mpp(NULL)
    {
      basePtr_mpp = new (CallBackEmpInterface *)[2];
    }

    void insert(const CallBackEmpInterface *obj_p)
    {
      CallBackEmpInterface *tempObj_p;

      tempObj_p = (CallBackEmpInterface *)obj_p;
     
      if(count !=2)
      {
        basePtr_mpp[count] = tempObj_p;
        ++count;
      }
    }

    void find(CallBackEmpInterface *critObj_p, bool (*wrapperFunc_p)(void *thisPtr, CallBackEmpInterface* obj1))
    {
      unsigned int i;

      for(i=0; i<2; ++i)
      {
        // here calling the calling back function compareEmpId to find the result
        if(0 == (wrapperFunc_p(critObj_p, basePtr_mpp[i])))
        {
          cout<<"Found the object with empId as "<<critObj_p->empId()<<"...\n\n" ;
          return;
        }
      }
      cout<<"The container does not have this empId...\n\n";
    }
   
   
  private:

    CallBackEmpInterface ** basePtr_mpp;
    static unsigned int count;
};

unsigned int CallBackEmpContainer::count = 0;

int main()
{
  cout<<"Implementation of Callback Function using Non-Static or Member Function ...\n";
  cout<<"----------------------------------------------------------------------------\n\n";
 
  CallBackEmployee *obj1 = new CallBackEmployee(1);
  CallBackEmployee *obj2 = new CallBackEmployee(2);
 
  CallBackEmpContainer cb;
  cb.insert(obj1);
  cb.insert(obj2);
 
  //Create the criterian, to find a object with empId as "1" in the container
  CallBackEmployee *obj3 = new CallBackEmployee(1);

  //Find the object of type criterian obj3 in the container and send the results
  cb.find(obj3, CallBackEmpInterface::wrapperToCompareEmpId);

  delete (obj1);
  delete (obj2);
  delete (obj3);

  return(0);
}

Output
------------

Implementation of Callback Function using Non-Static or Member Function ...
------------------------------------------------------------------------------------------

Ctor ::CallBackEmpInterface
Ctor ::CallBackEmployee
Ctor ::CallBackEmpInterface
Ctor ::CallBackEmployee
Ctor ::CallBackEmpInterface
Ctor ::CallBackEmployee


CallBackEmpInterface::wrapperToCompareEmpId


Calling member function CallBackEmpInterface::compareEmpId
Found the object with empId as 1...


Here in this example, compareEmpId is a member function of CallBackEmpInterface class, acts as a callback. This is done by having a static function called wrapperToCompareEmpId in the same class (which takes void pointer and required arguments to the callback function and in turn calls the compareEmpId function in it's implementation) and whose function pointer is sent to the find method and is used in the main function to find Employee with specific empId.

Implementation of Callback using Function Object or Functor

Functor is an object that acts like a function. Functor object overloads the parenthesis operator i.e. operator( ) that can return anything and can accept any number of parameters.

For Example: Here is a Functor that overloads operator ( ) to print a given string.

Code: Cpp

class MyFunctor
{
  void operator() (const string& str) const
  {
    cout<<str<<endl;
  }
}


The same way, we can overload operator() for comparison function and that can be called as a callback from an application.

The code


Code: Cpp

#include<iostream.h>

class CallBackEmpInterface
{
    unsigned int empId_m;

  public:

    CallBackEmpInterface()
    {
      cout<<"Ctor ::CallBackEmpInterface::default\n";
    }
   
    CallBackEmpInterface(unsigned int empId):empId_m(empId)
    {
      cout<<"Ctor ::CallBackEmpInterface\n";
    }
   
    unsigned int
    empId()
    {
      return (empId_m);
    }
   
    virtual bool callback(CallBackEmpInterface* obj1,
                          CallBackEmpInterface* obj2)
    {
      cout<<"CallBackEmpInterface::callBack \n";
    }
};

class CallBackEmployee : public CallBackEmpInterface
{
  public:

    CallBackEmployee(unsigned int empId):CallBackEmpInterface(empId)
    {
      cout<<"Ctor ::CallBackEmployee\n";
    }

    bool callback(CallBackEmpInterface* obj1, CallBackEmpInterface* obj2)
    {
      cout<<"\n\nCallBackEmployee::callBack \n";
     
      if(obj1->empId() == obj2->empId())
      {
        return(0); //---
      }
      else if(obj1->empId() < obj2->empId())
      {
        return(-1); //---
      }
      else
      {
        return(1); //---
      }
    }
};

class CallBackEmpContainer
{
  public:

    CallBackEmpContainer(): basePtr_mpp(NULL)
    {
      basePtr_mpp = new (CallBackEmpInterface *)[2];
    }

    void insert(const CallBackEmpInterface *obj_p)
    {
      CallBackEmpInterface *tempObj_p;
      tempObj_p = (CallBackEmpInterface *)obj_p;
     
      if(count !=2)
      {
        basePtr_mpp[count] = tempObj_p;
        ++count;
      }
    }
   
    bool operator () (CallBackEmpInterface* obj1, CallBackEmpInterface* obj2)
    {
      cout<<"\nCalling CallBackEmpInterface::operator () ...\n";
      return((*basePtr_mpp)->callback(obj1, obj2));
    }

  private:

    CallBackEmpInterface ** basePtr_mpp;
    static unsigned int count;
};

unsigned int CallBackEmpContainer::count = 0;

int main()
{
  cout<<"Implementation of Callback Function using Functor or FunctionObject ...\n";
  cout<<"------------------------------------------------------------------------\n\n";

  CallBackEmployee *obj1 = new CallBackEmployee(1);
  CallBackEmployee *obj2 = new CallBackEmployee(2);
 
  CallBackEmpContainer cb;
  cb.insert(obj1);
  cb.insert(obj2);
 
  //To find a object with empId as "1" in the container
  CallBackEmployee *obj3 = new CallBackEmployee(1);

  //compare objects empId
  if (0 == cb(obj1, obj3))
  {
    cout<<"Found the object with empId as "<<obj3->empId()<<"...\n\n" ;
  }
  else
  {
    cout<<"The container does not have this empId...\n\n";
  }

  delete (obj1);
  delete (obj2);
  delete (obj3);

  return(0);
}

Output
---------

Implementation of Callback Function using Functor or FunctionObject ...
-------------------------------------------------------------------------------------

Ctor ::CallBackEmpInterface
Ctor ::CallBackEmployee
Ctor ::CallBackEmpInterface
Ctor ::CallBackEmployee
Ctor ::CallBackEmpInterface
Ctor ::CallBackEmployee

Calling CallBackEmpInterface::operator () ...


CallBackEmployee::callBack
Found the object with empId as 1...


Here in this example, CallBackEmpContainer acts as a Functor, having the implementation for operator( ) with 2 arguments for comparison. This acts as a callback and is used in the main function to find the Employee with specific empId. This is done by creating a temporary criterian object of Employee with that specific empId (that needs to be found) and sent as a argument to operator ( ) function.

Hope this article helps in understanding the Callbacks and it's implementation.

thanks
Mridula.

References



To know more about Functor or Function Object refer:

Prefer Function Objects over Function Pointers
http://www.go4expert.com/showthread.php?t=16504

shabbir 2Sep2009 18:55

Re: Callback Implementation using Static Function, Member Function and Functor in C++
 
Nomination for Article of the month - Aug 2009 Started.


All times are GMT +5.5. The time now is 08:43.