Professional Documents
Culture Documents
The Function Pointer Tutorials
The Function Pointer Tutorials
Contents
1 Introduction to Function Pointers 2
1.1 What is a Function Pointer ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2 Introductory Example or How to Replace a Switch-Statement . . . . . . . . . . . . . . . . . . . . 2
1
1 Introduction to Function Pointers
Function Pointers provide some extremely interesting, efficient and elegant programming techniques. You can
use them to replace switch/if-statements, to realize your own late-binding or to implement callbacks. Unfor-
tunately – probably due to their complicated syntax – they are treated quite stepmotherly in most computer
books and documentations. If at all, they are addressed quite briefly and superficially. They are less error prone
than normal pointers cause you will never allocate or de-allocate memory with them. All you’ve got to do is
to understand what they are and to learn their syntax. But keep in mind: Always ask yourself if you really
need a function pointer. It’s nice to realize one’s own late-binding but to use the existing structures of C++
may make your code more readable and clear. One aspect in the case of late-binding is runtime: If you call a
virtual function, your program has got to determine which one has got to be called. It does this using a V-Table
containing all the possible functions. This costs some time each call and maybe you can save some time using
function pointers instead of virtual functions. Maybe not ... 1
//-----------------------------------------------------------------------------------------
// 1.2 Introductory Example or How to Replace a Switch-Statement
// Task: Perform one of the four basic arithmetic operations specified by the
// characters ’+’, ’-’, ’*’ or ’/’.
2
case ’*’ : result = Multiply(a, b); break;
case ’/’ : result = Divide (a, b); break;
}
cout << "switch: 2+5=" << result << endl; // display result
}
Important note: A function pointer always points to a function with a specific signature! Thus all functions,
you want to use with the same function pointer, must have the same parameters and return-type!
3
the attribute keyword: Write the function definition followed by the keyword attribute and then state the
calling convention in double parentheses.3
// 2.2 define the calling convention
void __cdecl DoIt(float a, char b, char c); // Borland and Microsoft
void DoIt(float a, char b, char c) __attribute__((cdecl)); // GNU GCC
// C
int DoIt (float a, char b, char c){ printf("DoIt\n"); return a+b+c; }
int DoMore(float a, char b, char c){ printf("DoMore\n"); return a-b+c; }
// C++
class TMyClass
{
public:
int DoIt (float a, char b, char c){ cout << "TMyClass::DoIt" << endl; return a+b+c; };
int DoMore(float a, char b, char c){ cout << "TMyClass::DoMore" << endl; return a-b+c; };
/* more of TMyClass */
};
pt2Member = TMyClass::DoIt; // assignment
pt2Member = &TMyClass::DoMore; // alternative using address operator
// C
if(pt2Function == &DoIt)
printf("pointer points to DoIt\n");
// C++
if(pt2Member == &TMyClass::DoMore)
cout << "pointer points to TMyClass::DoMore" << endl;
4
// 2.5 calling a function using a function pointer
int result1 = pt2Function (12, ’a’, ’b’); // C short way
int result2 = (*pt2Function) (12, ’a’, ’b’); // C
TMyClass instance;
int result3 = (instance.*pt2Member)(12, ’a’, ’b’); // C++
int result4 = (*this.*pt2Member)(12, ’a’, ’b’); // C++ if this-pointer can be used
//-----------------------------------------------------------------------------------------
// 2.6 How to Pass a Function Pointer
// <pt2Func> is a pointer to a function which returns an int and takes a float and two char
void PassPtr(int (*pt2Func)(float, char, char))
{
float result = pt2Func(12, ’a’, ’b’); // call using function pointer
// execute example code - ’DoIt’ is a suitable function like defined above in 2.1-4
void Pass_A_Function_Pointer()
{
cout << endl << "Executing ’Pass_A_Function_Pointer’" << endl;
PassPtr(&DoIt);
}
//-----------------------------------------------------------------------------------------
// 2.7 How to Return a Function Pointer
// ’Plus’ and ’Minus’ are defined above in 2.1-4. They return a float and take two float
// direct solution
// function takes a char and returns a pointer to a function which is taking two
// floats and returns a float. <opCode> specifies which function to return
float (*GetPtr1(const char opCode))(float, float)
{
if(opCode == ’+’) return &Plus;
if(opCode == ’-’) return &Minus;
}
5
// function takes a char and returns a function pointer which is defined as a
// type above. <opCode> specifies which function to return
pt2Func GetPtr2(const char opCode)
{
if(opCode == ’+’) return &Plus;
if(opCode == ’-’) return &Minus;
}
//-----------------------------------------------------------------------------------------
// 2.8 How to Use Arrays of C Function Pointers
// C
// type-definition: ’pt2Function’ now can be used as type
typedef int (*pt2Function)(float, char, char);
// assign the function’s address - ’DoIt’ and ’DoMore’ are suitable functions
// like defined above in 2.1-4
funcArr[0] = &DoIt;
funcArr[1] = &DoMore;
/* more assignments */
6
// C++
// type-definition: ’pt2Member’ now can be used as type
typedef int (TMyClass::*pt2Member)(float, char, char);
// assign the function’s address - ’DoIt’ and ’DoMore’ are suitable member functions
// of class TMyClass like defined above in 2.1-4
funcArr[0] = &TMyClass::DoIt;
funcArr[1] = &TMyClass::DoMore;
/* more assignments */
field points to the first element of the field which is to be sorted, nElements is the number of items in the field,
sizeOfAnElement the size of one item in bytes and cmpFunc is the pointer to the comparison function. This
comparison function takes two void-pointers and returns an int. The syntax, how you use a function pointer
as a parameter in a function-definition looks a little bit strange. Just review, how to define a function pointer
and you’ll see, it’s exactly the same. A callback is done just like a normal function call would be done: You
just use the name of the function pointer instead of a function name. This is shown below. Note: All calling
arguments despite the function pointer were omitted to focus on the relevant things.
4 Taken from the Borland Compiler C++ 5.02 (BC5.02)
7
void qsort( ... , int(_USERENTRY *cmpFunc)(const void*, const void*))
{
/* sort algorithm - note: item1 and item2 are void-pointers */
if(*a > *b) return 1; // first item is bigger than the second one -> return 1
else
if(*a == *b) return 0; // equality -> return 0
else return -1; // second item is bigger than the first one -> return -1
}
8
3.5 How to Implement a Callback to a non-static C++ Member Function ?
Pointers to non-static members are different to ordinary C function pointers since they need the this-pointer
of a class object to be passed. Thus ordinary function pointers and non-static member functions have different
and incompatible signatures! If you just want to callback to a member of a specific class you just change your
code from an ordinary function pointer to a pointer to a member function. But what can you do, if you want
to callback to a non-static member of an arbitrary class? It’s a little bit difficult. You need to write a
static member function as a wrapper. A static member function has the same signature as a C function! Then
you cast the pointer to the object on which you want to invoke the member function to void* and pass it to
the wrapper as an additional argument or via a global variable.5 Of course you’ve also got to pass the
calling arguments for the member function. The wrapper casts the void-pointer to a pointer to an instance of
the correct class and calls the member function. Below you find two examples:
Example A: Pointer to a class instance passed as an additional argument The function DoItA does
something with objects of the class TClassA which implies a callback. Therefore a pointer to an object of class
TClassA and a pointer to the static wrapper function TClassA::Wrapper To Call Display are passed to DoItA.
This wrapper is the callback-function. You can write arbitrary other classes like TClassA and use them with
DoItA as long as these other classes provide the necessary functions. Note: This solution may be useful if you
design the callback interface yourself. It is much better than the second solution which uses a global variable.
//-----------------------------------------------------------------------------------------
// 3.5 Example A: Callback to member function using an additional argument
// Task: The function ’DoItA’ makes something which implies a callback to
// the member function ’Display’. Therefore the wrapper function
// ’Wrapper_To_Call_Display is used.
class TClassA
{
public:
/* more of TClassA */
};
// call member
mySelf->Display(string);
}
pt2Function(pt2Object, "hi, i’m calling back using a argument ;-)"); // make callback
}
5 If you use a global variable it is very important that you make sure that it will always point to the correct object!
9
// execute example code
void Callback_Using_Argument()
{
// 1. instantiate object of TClassA
TClassA objA;
Example B: Pointer to a class instance is stored in a global variable The function DoItB does
something with objects of the class TClassB which implies a callback. A pointer to the static wrapper function
TClassB::Wrapper To Call Display is passed to DoItB. This wrapper is the callback-function. The wrapper
uses the global variable void* pt2Object and explicitly casts it to an instance of TClassB. It is very important,
that you always initialize the global variable to point to the correct class instance. You can write arbitrary other
classes like TClassB and use them with DoItB as long as these other classes provide the necessary functions.
Note: This solution may be useful if you have an existing callback interface which cannot be changed. It is
not a good solution because the use of a global variable is very dangerous and could cause serious errors.
//-----------------------------------------------------------------------------------------
// 3.5 Example B: Callback to member function using a global variable
// Task: The function ’DoItB’ makes something which implies a callback to
// the member function ’Display’. Therefore the wrapper function
// ’Wrapper_To_Call_Display is used.
class TClassB
{
public:
/* more of TClassB */
};
// call member
mySelf->Display(string);
}
10
// execute example code
void Callback_Using_Global()
{
// 1. instantiate object of TClassB
TClassB objB;
//-----------------------------------------------------------------------------------------
// 4.2 How to Implement Functors
11
public:
// dummy class A
class TClassA{
public:
TClassA(){};
void Display(const char* text) { cout << text << endl; };
/* more of TClassA */
};
// dummy class B
class TClassB{
public:
TClassB(){};
void Display(const char* text) { cout << text << endl; };
/* more of TClassB */
};
// main program
int main(int argc, char* argv[])
{
// 1. instantiate objects of TClassA and TClassB
TClassA objA;
TClassB objB;
// 3. create array with pointers to TFunctor, the base class and ...
12
TFunctor** vTable = new TFunctor*[2];
// 5. release
delete[] vTable;
13