C++: Function Pointers

We've previously talked about pointers to data structures and class objects, however in C++ we can also have pointers to functions. These pointers behave a little bit differently that the other pointers we've come across so far, but by the end of this tutorial you should know how to use function pointers, as well as knowing the basics of what you can and cannot do with them.

The most confusing thing about function pointers is probably their syntax - you write the data-type of the function(s) the pointer will point to, then the name of the pointer, prepended by an asterisk, in brackets, then some brackets with the parameters the types of function the pointer points to will take. As this implies, function pointers must point to functions with the same data-type and parameter types (as well as number of parameters). The syntax, visually, looks like data-type (*pointerName)(parameters);.

The easiest way to get used to function pointers is to just keep using them. The simplest example, perhaps, would be to create two simple void functions, and then point the function pointer to each, calling the functions via the pointer after each assignment. This could be accomplished, much as you'd expect with "normal" pointers, as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void one() { cout << "One\n"; }
void two() { cout << "Two\n"; }


int main()
{
	void (*fptr)(); //Declare a function pointer to voids with no params

	fptr = &one; //fptr -> one
	*fptr(); //=> one()

	fptr = &two; //fptr -> two
	*fptr(); //=> two()

	return 0;
}

The above would work as expected, outputting "One" and then "Two". When setting and accessing the value of function pointers, note that the dereference and "address of" operators aren't actually necessary - usually they aren't used for the sake of simplicity, as shown in the modified snippet below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void one() { cout << "One\n"; }
void two() { cout << "Two\n"; }


int main()
{
	void (*fptr)(); //Declare a function pointer to voids with no params

	fptr = one; //fptr -> one
	fptr(); //=> one()

	fptr = two; //fptr -> two
	fptr(); //=> two()

	return 0;
}

If a function pointer needs to point to functions that take parameters, the data-types of these parameters can simply be separated by commas in the function pointer declaration. Take for example the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void one(int a, int b) { cout << a+b << "\n"; }
void two(int a, int b) { cout << a*b << "\n"; }


int main()
{
	void (*fptr)(int, int); //Declare a function pointer to voids with two int params

	fptr = one; //fptr -> one
	fptr(12, 3); //=> one(12, 3)

	fptr = two; //fptr -> two
	fptr(5, 4); //=> two(5, 3)

	return 0;
}

Just to make sure you understand the syntax of function pointers, I recommend trying to create a few of these very basic examples - a function pointer to functions which take in, and return, doubles for example.

We can also create arrays of function pointers. These aren't as scary as they sound, and they're simply created much like you would with an array of "normal" pointers, by specifying a number of elements in square brackets next to the pointer name. If we wanted a function pointer array which contained pointers to both functions "one" and "two" in elements of index 0 and 1, we could use the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void one(int a, int b) { cout << a+b << "\n"; }
void two(int a, int b) { cout << a*b << "\n"; }


int main()
{
	void (*fptr[2])(int, int);
	fptr[0] = one;
	fptr[1] = two;

	fptr[0](12, 3); //one(12, 3)
	fptr[1](5, 4); //two(5, 3)

	return 0;
}

The above would work exactly as our previous one did, apart from both functions will be accessible any time by using "fptr[0]" and "fptr[1]". As you can probably tell, practical yet simple examples of function pointers aren't particularly easy to come up with - generally function pointers become useful due to the fact that we can indirectly call a function without knowing at compile-time which function we're going to call. Perhaps "fptr[0]" in our example may change to a pointer to a third function, "three", in some conditional situation, in which case "fptr[0]" will yield different results in different circumstances. We'll cover a practical example with a basis like this in a minute. Before we move on to a "different type" of function pointers and create this more practical example though, be aware that pointer arithmetic doesn't work on function pointers.

We can also create member function pointers in C++! The syntax is essentially the same as function pointers, however the class name followed by the scope resolution operator prepends the pointer name - so data-type (ClassName::*pointerName)(parameters);. The syntax is messy, but it works. With member functions, the "address of" and dereference operators are necessary during assignment and access - because of this, calling member functions via member function pointers on class objects usually requires a syntax that looks like object.*pointerName to dereference the pointer before performing the member function on the object. This is all, once again, quite difficult to explain in words - so a simple code example may be of help:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Number
{
public:
	int i;
	Number() { i = 0; }
	int one() { return i+1; }
	int two() { return i+2; }
};

int main()
{
	Number object; //Create a new 'Number' object named 'object'
	int (Number::*NumberPtr)(); //Declare a pointer to member functions in "Number" of type 'int' with takes no params

	NumberPtr = &Number::one;
	cout << (object.*NumberPtr)() << endl;

	NumberPtr = &Number::two;
	cout << (object.*NumberPtr)() << endl;

	return 0;
}

The above should work as expected - the difference between our previous examples clearly being that this pointer could be used to indirectly call a member function upon any "Number" object. Like "regular" function pointers, you can also create arrays of member function pointers - so the following would perform the same as the snippet above, but would leave "NumberPtr[0]" and "NumberPtr[1]" available for calling any time:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// ... class stuff ...

int main()
{
	Number object; //Create a new 'Number' object named 'object'
	int (Number::*NumberPtr[2])(); //Declare a pointer array with two elements which are pointers to member functions in "Number" of type 'int' with takes no params

	NumberPtr[0] = &Number::one;
	NumberPtr[1] = &Number::two;

	cout << (object.*NumberPtr[0])() << endl;	
	cout << (object.*NumberPtr[1])() << endl;

	return 0;
}

With member function pointers covered, at least conceptually, I once again recommend you take a quick break from this tutorial to try this for yourself. It's important that you get used to the syntax and also understand what function pointers (of this kind) are capable of.

So to tie off this tutorial, we're going to create a quick example with a practical use of a member function pointer. The plan is to create a basic class named "Employee" which will hold some basic information about any given employee of a company. Most importantly, this class will contain a "Pay" member function which will call a private function via a function pointer to get the salary of the employee (based on the number of hours they've worked). The member function pointer will actually be a member of the "Employee" class, and it comes in handy when we decide that employees are either normal or experienced -- the member function pointer for experienced users will point towards a different private member function which will calculate a higher wage for experienced employees. Again, this isn't all that easy to explain, but from reading this (and previous) tutorial(s), you should (hopefully) understand the commented code that follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class Employee
{
public:
	Employee()
	{
		wageCalc = &Employee::CalculateWage; //wageCalc -> CalculateWage
	}
	void UpgradeToExperienced()
	{
		wageCalc = &Employee::CalculateExperiencedWage; //wageCalc -> CalculateExperiencedWage
	}
	double Pay(double hours)
	{
		return (this->*wageCalc)(hours); //=> object.*wageCalc(hours)
	}
private:
	double (Employee::*wageCalc)(double hours);  //The member function ptr
	double CalculateWage(double hours)
	{
		return 10*hours;
	}
	double CalculateExperiencedWage(double hours)
	{
		return 20*hours;
	}

};

int main()
{
	Employee one;
	cout << one.Pay(10) << endl;
	one.UpgradeToExperienced();
	cout << one.Pay(10) << endl;

	return 0;
}

The above should show "100" and then "200", as the employee, "one", is first calculated to be paid as a "regular" employee, and then as an experienced employee.