FruitNotes beta
Your All-in-One Online Notebook
FruitNotes Blogs | Home  
What is Function Object?
Last updated at (Fri Mar 21 23:44:21 2008)
Posted by: Ankur Barua
0%




Although pointers to functions are widely used for implementing function callbacks, C offers a significantly superior alternative to them, namely function objects. Function objects (also called "functors") are ordinary class objects that overload the () operator. Thus, syntactically, they behave like ordinary functions.

There are several advantages in using a function object instead of a pointer to function. First, they are more resilient to design changes because the object can be modified internally without changing its external interface. A function object can also have data members that store the result of a previous call. When using ordinary functions, you need to store the result of a previous call in a global or a local static variable. However, global and local static variables have some undesirable characteristics. Finally, compilers can inline a call made through a function object, thereby enhancing performance even further. In contrast, it is nearly impossible to inline a function call made through a pointer.

This solution will show how to define and use a function object that implements a negation operation. The first step consists of declaring an ordinary class and overloading the () operator:

  class Negate   {  public:     int operator() (int n) { return -n;}   };

The overloaded () might look a bit confusing because it has two pairs of parentheses. Remember that the first pair is always empty because it serves as the operator's name; the parameter list appears in the second pair of parentheses. Unlike other overloaded operators, whose number of parameters is fixed, the overloaded () operator may take any number of parameters.

Because the built-in negation operator is unary (it takes only a single operand), our overloaded () operator also takes a single parameter. The return type is identical to the parameter's type—int, in our example. The function body is trivial; it simply returns the negated argument.

Using the Function Object
We now define a function named Callback() to test our function object. Callback() takes two arguments: an int and a reference to Negate. Callback() treats neg, the function object, as if it were a function's name:

  #include <iostream>  using std::cout;  void Callback(int n, Negate & neg)   {    int val = neg(n);  //1 invoke overloaded ()     cout << val;  }

Don't let the syntax mislead you: neg is an object, not a function. The compiler transforms the line numbered 1 into the following:

  int val = neg.operator()(n);

In general, function objects do not define constructors and destructors. Therefore, they do not incur any overhead during their creation and destruction. As previously noted, the compiler can inline the overloaded operator's code, thereby avoiding the runtime overhead associated with a full-blown function call.

To complete the example, we need a main() driver to pass arguments to Callback():

  int main()   {   Callback(5, Negate() ); //output -5  }

The program passes the integer 5 and a temporary Negate object to Callback(). As expected, the program displays -5.

Template Function Objects
Our example was confined to type int. However, one of the advantages of function objects is their generic nature. You can define the overloaded () operator as a member template so that it can work for any datatype: double, __int64 or char as follows:

  class GenericNegate  {  public:    template <class T> T operator() (T t) const {return -t;}  };  int main()  {   GenericNegate negate;   cout<< negate(5.3333); // double   cout<< negate(10000000000i64); // __int64  }

Achieving this flexibility with ordinary callback functions is much more difficult.

Function Objects in the Standard Library
The C Standard Library defines several useful function objects that can be plugged into STL algorithms. For example, the sort() algorithm takes a predicate object as its third argument. A predicate object is a templatized function object that returns a Boolean result. You can pass the predicates greater<> or less<> to sort() to force a descending or ascending sorting order, respectively:

  #include <functional> // for greater<> and less<>  #include <algorithm> //for sort()   #include <vector>  using namespace std;    int main()  {     vector <int> vi;   //..fill vector   sort(vi.begin(), vi.end(), greater<int>() );//descending    sort(vi.begin(), vi.end(), less<int>() );  //ascending  } 


Rate this blog

   Report Abuse


Comments


Leave your comment(s) below:
To start Your own Blog




Other Blogs
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
» 
2007 FruitNotes.com - All Rights Reserved.