Hello again! In this video, we are going to look at function pointers. The executable code for a function,
the code that gets run when the function is called, is stored in memory. And we can actually guess a pointer
to that code.
We can take the address of the function, and then that will be a pointer to the start of that code.
The actual type of this pointer is rather ugly!
So it is declared as a pointer. Because of the operator precedence rules in C++, we have to put it inside
brackets. Without the brackets,
this would be interpreted as a function that returns pointer to void. With the asterisk inside the brackets,
so points to a function, and this function takes two ints and returns void.
So that is a pointer to the function. Generally, working with function pointer types is pretty ugly.
We can avoid it in the declaration by using auto, but you need it in other places as well.
So it is a good idea to use a type alias.
So this is where the "using" keyword comes in.
So we have "using" and then the alternative name, "pfunc", equals, and then we have the type.
So this is without the variable name.
So this is a pointer to a function which takes two ints and returns void.
A function pointer is something called a callable object.
So this is something that behaves like a variable, but it can be called like a function.
So it is a kind of hybrid between data and code.
We can copy it, we can pass it around, but we can also put a couple of buckets after it and call
a function.
And to do that, we just dereference the pointer. Again, we need the brackets.
And then we put a couple of brackets, with the arguments inside.
This means that a function pointer is what is called a "first-class object". So we can pass it as an argument
to another function call and we can return it from another function call.
So here is some code.
We have a function which just adds the arguments together and prints out their sum.
Nothing terribly exciting.
We get a pointer to this function.
In fact, you can miss out the ampersand. And then we call the function through the pointer by dereferencing
the pointer.
And again, the asterisk is optional.
I prefer to leave the all in for consistency.
The reason is that, when you return a pointer from a function, the asterisk is not optional. And it looks
better if you have the asterisks and stars in, I think.
But that is just a question of style.
So this is going to call the function with arguments 1 and 2.
So we should see "1 + 2 = 3", and indeed we do get that.
To pass a function pointer as an argument, we just put the type in the function declaration. And then
we put the type and the argument's name in the definition.
So this is some function which takes two ints and a pointer too, pfunc, and then in the body of the function
you can call the function.
You can call it with the function arguments or some other arguments, if you wish.
And also, we can return a function pointer from a function call.
So this is basically the same code again, except we go through functions to return the function call.
So this is basically the same code again, except we have a bit more indirection. So we have the same
function again.
There is an alias for it. And the asterisk is not optional in here!
If you prefer the older C++ typedef, you can use that instead.
Then we have a function which will take the function pointer as an arguument and call the function.
Again, the asterisk is optional.
We have another function which will return a function pointer. Actually, let's put the ampersand in
there.
So this will return a pointer to the function up here.
That will be returned there. And then, in the main function we use that return value as the argument to the
some_func here, which will call the function up here.
So it is all a bit convoluted. But it is just to show you how the syntax works, really.
And then we get the same result again.
Function points were inherited from C, so they are pretty basic, and they have some drawbacks.
The main use for function pointers is for writing what are called "callbacks".
If you are calling a function from a GUI, or an operating system API, or framework, or some event
driven code, quite often there is an argument which is a function pointer. And you can provide a function
there, which will do something when something happens.
So you can say that you want the operating system or the GUI to call this function if a particular
event happens.
For example, if the user clicks on a button, you can ask them to call this function, which will open
a new window. Something like that.
These are raw pointers. They can be overwritten by another function of the same type.
They can be set to null and they can be uninitialized.
So there's quite a bit of scope for problems here.
Fortunately, they don't involve memory management! And also the syntax is pretty horrible.
So there are better ways of doing this, and we'll look at those later on in the course.
Okay, so that is it for this video.
I will see you next time.
But until then, keep coding!