Prefer Function Objects over Function Pointers

Mridula's Avatar author of Prefer Function Objects over Function Pointers
This is an article on Prefer Function Objects over Function Pointers in C++.

Introduction



This article talks about Function Object and it's uses over Function Pointers

Background



A Function Object, is an Object of a class that defines an operator () and can be called as a function. When a function object is used as a function, the function call operator() is invoked and does the similar way as by calling a function.

Remember that the overloaded operator () can have a varying number of arguments, and any return value. These function objects are frequently used in numerical methods implementation.

It's uses :

1. More resilient to design changes as objects can be modified without affecting it's external interface.

2. Function objects are faster than functions as many a times an invocation of a function object, can be expanded in-line and thus eliminating the overhead of a function call. Whereas it is nearly impossible to inline a non-static function that is called through functions poiners.

3. It can emobody a generic alogorithm by means of a member template.

4. It is possible to perform very sophisticated operations without actually writing a new function object, simply by combining predefined function objects, like the way currently it is done in STL.

5. Function objects are more powefull than functions, since they can have data members and there carry around information or internal states.

An example to illustrate the last point is below:

Code: Cpp
#include<iostream.h>

class iotaGen
{
public:
  iotaGen (int start = 0) : current(start) { }
  int operator() () { return current++; }
 
private:
  int current;
};

void initializeArray(int (*arr), iotaGen &gen)
{
  int i;
  i=0;

  while(20 > i)
  {
    arr[i] = gen();
    cout<<"arr["<<i<<"]="<<arr[i]<<"\n";
    ++i;
  }
}

int main()
{
  iotaGen a(1);
  int arr[20];
 
  cout<<"Initializing array using Function Object...\n\n";
  initializeArray(arr, a);
 
  return (0);
}

Output:

Initializing array using Function Object...

arr[0]=1
arr[1]=2
arr[2]=3
arr[3]=4
arr[4]=5
arr[5]=6
arr[6]=7
arr[7]=8
arr[8]=9
arr[9]=10
arr[10]=11
arr[11]=12
arr[12]=13
arr[13]=14
arr[14]=15
arr[15]=16
arr[16]=17
arr[17]=18
arr[18]=19
arr[19]=20

This is an example where, iotaGen object maintains a current value, which can be set by the constructor, or defaults to zero. Each time the function-call operator() is invoked, the current value is returned, and also incremented.

This is also used in the creation of a generator, to be used with the generic algorithm std::generate(). A generator is simply a function object that takes no arguments and returns a new value each time it is invoked.

Using iotaGen object, the following call on the standard library function generate() will initialize a vector of 20 elements with the values 1 through 20:

Code: Cpp
vector<int> aVec(20);
generate (aVec.begin(), aVec.end(), iotaGen(1));

Here is another example where Function Object acts as a Generic Compare Function. Here in the main function - cf is a object of CompareFunc, that is passed to a function called findMatch and so works as a callback function.

The code


Code: Cpp
#include <iostream.h>

template <class Type>
class CompareFunc
{
  public:
    bool operator()(const Type &x, const Type &y)
    {
      return (x==y);
    }
};

void findMatch(const char* str1, const char* str2, CompareFunc<const char*> &cf)
{
 if( cf(str1, str2))
 {
   cout<<str1<<" & "<<str2<<" -> matches\n";
   
 }
 else
 {
   cout<<str1<<" & "<<str2<<" -> does not match\n";
 }
}

int main()
{
  CompareFunc<const char*> cf;
 
   //calling function findMatch by CompareFunc object "cf"
  findMatch("Hello","World",cf);
  findMatch("Hello","Hello",cf);

  return(0);
}

output:
./a.out
Hello & World -> does not match
Hello & Hello -> matches
shabbir's Avatar, Join Date: Jul 2004
Go4Expert Founder
Article of the month competition nomination started here
Mike Razar's Avatar, Join Date: Mar 2010
Newbie Member
I am a big fan of function objects. Do you think that all "global" functions are better defined as objects? How about member functions in classes? I usually define fctn. objects inheriting from unary or binary function classes. Is there ever a reason not to do that?

I find the language a bit confusing. Is the class the function object or is each instance of the class a function object. I think the latter.
yannick_lethanh's Avatar, Join Date: Feb 2011
Newbie Member
First Mridula thank you for the nice post. I have a question though. You said about the advantages of using function objects over function pointers is that they are "1. More resilient to design changes as objects can be modified without affecting it's external interface."
Although I totally agree with the next remarks I am not quite sure about what you mean about this one. Thinking of functions it seems that you can also change the function's behavior without having to change its prototype.
If you meant that you can easily add new input params to function objects while you would need to change function's prototype it's not certain either as you would have to change the constructor's prototype in order to pass the new parameters to the internal state of the function object.

I know the post is quite old so I may not receive any answer but I hope there will be someone ending up reading this thread.

To answer Mike's questions.

All global functions shouldn't be systematically replaced with function objects. The article is only referring to the advantage of using function objects over function pointers. For a plain function there is no point creating an function object or call it through a pointer. Most of the time a "normal" call will be enough.
Function pointers and function objects really triggers in when you want to reuse the same code for different behaviors. The variation in behaviors will be implemented through "pointing" to a different function or passing a different function object. If you will always use the same behavior you should save you the pain of writing a new class or the loss in performance of indirecting a pointer to a function.
Also I would make one comment about the use of function objects over function pointers: this should not be a systematic rule. I definitely do agree with points 4 and 5 of Mridula's post but point 2 is not so obvious: inlining a function may not always mean better performance. It can actually result in a poorer performance and for this reason although you specify the function to be inline your compiler may simply ignore it if it thinks it will result in a worse performance.
So if you just don't need properties commented in points 3, 4 and 5 and you are not sure inlining a function will result in a better performance you may just use a function pointer.
In the case you just need to call a for_each algorithm on a simple function that will just perform some basics operations on the elements of the container you may not need to have to write a whole class just to provide it with a () operator.
At this point I will add one case when it is better to using function objects rather than function pointers. It's when you want to have a set of behaviors that are very similar to each other. In this case you may implement them through function objects that belong to the same hierarchy of classes and this way take advantage of inheritance and polymorphism.
My general point is you can't just say use this one rather that that one. It's sure function objects offer more power than function pointers but sometime it must be too much power than what you really need. There is no general rule. You have to use what better suits your needs.

About using function objects inheriting from unary and binary function classes, it's a good idea as many STL algorithms only apply to objects deriving from these classes. Although this should not need be always the case. The simplest reason not to do that is when you need functions with no params or more than two params.

Last: it's true that the language is unclear. A function object just means an object that behaves like a function. Strictly speaking it represents the instantiation of a class redefining operator(). But since the use you will make of function objects will always be through operator() and that this operator will not be static (otherwise it means you are not using the internal state of the class so it would question the use of a function object over a function pointer) then it means you will always have to instantiate a class into an object so although you are perfectly right saying it's not strictly correct we may just speak of object and class as if they were the same.