Last modified on 14 June 2009, at 17:04

C++ Programming/Operators/Pointers/To Functions

Pointers to functionsEdit

The pointers we have looked at so far have all been data pointers, pointers to functions (more often called function pointers) are very similar and share the same characteristics of other pointers but in place of pointing to a variable they point to functions. Creating an extra level of indirection, as a way to use the functional programming paradigm in C++, since it facilitates calling functions which are determined at runtime from the same piece of code. They allow passing a function around as parameter or return value in another function.

Using function pointers has exactly the same overhead as any other function call plus the additional pointer indirection and since the function to call is determined only at runtime, the compiler will typically not inline the function call as it could do anywhere else. Because of this characteristics, using function pointers may add up to be significantly slower than using regular function calls, and be avoided as a way to gain performance.

Note:
Function pointers are mostly used in C, C++ also permits another constructs to enable functional programming that are called functors (class type functors and template type functors) that have some advantages over function pointers.

To declare a pointer to a function naively, the name of the pointer must be parenthesized, otherwise a function returning a pointer will be declared. You also have to declare the function's return type and its parameters. These must be exact!

Consider:

int (*ptof)(int arg);

The function to be referenced must obviously have the same return type and the same parameter type as that of the pointer to function. The address of the function can be assigned just by using its name, optionally prefixed with the address-of operator &. Calling the function can be done by using either ptof(<value>) or (*ptof)(<value>).

So:

int (*ptof)(int arg);
int func(int arg){
    //function body
}
ptof = &func; // get a pointer to func
ptof = func;  // same effect as ptof = &func
(*ptof)(5);   // calls func
ptof(5);      // same thing.

A function returning a float can't be pointed to by a pointer returning a double. If two names are identical (such as int and signed, or a typedef name), then the conversion is allowed. Otherwise, they must be entirely the same. You define the pointer by grouping the * with the variable name as you would any other pointer. The problem is that it might get interpreted as a return type instead.

It is often clearer to use a typedef for function pointer types; this also provides a place to give a meaningful name to the function pointer's type:

typedef int (*int_to_int_function)(int);
int_to_int_function ptof;
int *func (int);   // WRONG: Declares a function taking an int returning pointer-to-int.
int (*func) (int); // RIGHT: Defines a pointer to a function taking an int returning int.

To help reduce confusion, it is popular to typedef either the function type or the pointer type:

typedef int ifunc (int);    // now "ifunc" means "function taking an int returning int"
typedef int (*pfunc) (int); // now "pfunc" means "pointer to function taking an int returning int"

If you typedef the function type, you can declare, but not define, functions with that type. If you typdef the pointer type, you cannot either declare or define functions with that type. Which to use is a matter of style (although the pointer is more popular).

To assign a pointer to a function, you simply assign it to the function name. The & operator is optional (it's not ambiguous). The compiler will automatically select an overloaded version of the function appropriate to the pointer, if one exists:

int f (int, int);
int f (int, double);
int g (int, int = 4);
double h (int);
int i (int);
 
int (*p) (int) = &g; // ERROR: The default parameter needs to be included in the pointer type.
p = &h;              // ERROR: The return type needs to match exactly.
p = &i;              // Correct.
p = i;               // Also correct.
 
int (*p2) (int, double);
p2 = f;              // Correct: The compiler automatically picks "int f (int, double)".

Using a pointer to a function is even simpler - you simply call it like you would a function. You are allowed to dereference it using the * operator, but you don't have to:

#include <iostream>
 
int f (int i) { return 2 * i; }
 
int main ()
 {
  int (*g) (int) = f;
  std::cout<<"g(4) is "<<g(4)<<std::endl;    // Will output "g(4) is 8"
  std::cout<<"(*g)(5) is "<<g(5)<<std::endl; // Will output "g(5) is 10"
  return 0;
 }