WEBVTT

00:00.120 --> 00:07.140
Hello again! In this video, we are going to look at member function pointers. C++ allows us to define

00:07.140 --> 00:13.530
pointers to member functions of classes. Using them is more complicated than with normal function pointers.

00:13.530 --> 00:16.320
Pointers to non-member functions.

00:17.220 --> 00:23.490
The member function pointers use different syntax, and we may also need to provide the object that they are

00:23.490 --> 00:23.940
called on.

00:24.840 --> 00:27.210
When you call a member function, you have to provide an object.

00:27.540 --> 00:33.060
Normally the compiler will do that for you, if you are calling it directly. But if you are going through a pointer

00:33.060 --> 00:34.620
then you may need to do that yourself.

00:35.730 --> 00:41.550
Member function pointers cannot be called directly. Unlike function pointers, we have to explicitly

00:41.730 --> 00:46.200
dereference them. And that means that member function pointers are not callable objects.

00:49.650 --> 00:56.170
So let's say we have a class with a member function and we want to have a pointer to this member function.

00:57.570 --> 01:00.890
The syntax for doing this is even worse than with normal function pointers,

01:00.890 --> 01:03.150
because we have to give the name of the class as well.

01:03.780 --> 01:06.890
So "pfunc" is a pointer to a member of "Test".

01:07.440 --> 01:11.430
It takes int and const string ref, and returns void.

01:12.540 --> 01:17.130
And then, to initialize this variable, we have to give it the address of the member function.

01:17.460 --> 01:19.740
And the ampersand is compulsory here.

01:20.220 --> 01:22.830
It is not optional, like it is with function pointers.

01:26.300 --> 01:28.450
To call a member function pointer,

01:28.460 --> 01:35.660
we first need an object. Then we need to get the pointer as a member of the object, the member function

01:35.660 --> 01:36.080
pointer.

01:36.440 --> 01:37.610
And then we dereference it.

01:37.940 --> 01:43.160
So we are doing both the "dot" and the "star" operations. And there is actually a special operator for this, which

01:43.160 --> 01:43.700
does both.

01:44.480 --> 01:47.210
So that is how you call a pointer to member function,

01:47.570 --> 01:53.600
when you have an object. If you have a pointer to an object, then you need to use the arrow operator for

01:53.600 --> 01:55.640
the member access.

01:56.120 --> 01:58.040
So there is an "arrow star" operator.

02:00.150 --> 02:02.340
So that is an operator with three characters.

02:04.840 --> 02:08.310
C++11 has some features which help us when we're working with member

02:08.320 --> 02:14.470
function pointers. First of all, the auto keyword, so we can just initialize the pointer with

02:14.470 --> 02:17.800
the address, and let the compiler work out what the type is.

02:19.210 --> 02:21.220
And we can also use type aliases.

02:21.580 --> 02:27.640
So if we want to create a vector, for example, of member function pointers, we can create a type alias

02:27.640 --> 02:28.600
and then use that.

02:29.200 --> 02:30.850
So that makes the code look a lot cleaner.

02:32.860 --> 02:33.940
So let's try this out.

02:33.940 --> 02:35.920
We have our class with the member function.

02:36.970 --> 02:46.720
We define a pointer to this member function. Or there is the C++11 syntax. And then we call the

02:47.110 --> 02:48.610
member function through the pointer.

02:50.140 --> 02:50.770
And there we are.

02:53.280 --> 03:00.810
C++11 has a function called mem_fn() in the <functional> header, and this can be used to convert a member function

03:00.810 --> 03:02.910
pointer into a callable object.

03:03.750 --> 03:09.960
So we pass our member function pointer as an argument to mem_fn(), and this will return a callable object.

03:11.310 --> 03:17.370
When we invoke this callable, we need to pass an object for the function to be called on.

03:17.970 --> 03:21.600
So we need to give an object of the class as the first argument.

03:22.110 --> 03:24.630
And then we give the arguments to the member function call.

03:26.840 --> 03:29.150
So, the same member function again.

03:32.280 --> 03:34.580
We use the C++11 syntax this time.

03:34.920 --> 03:38.640
Then we called mem_fn(). We get our callable object.

03:39.000 --> 03:42.300
And then we invoke it with an object of the class as the first argument.

03:46.730 --> 03:49.520
We can also use bind() with member function pointers.

03:50.000 --> 03:51.470
So let's go back to the example

03:51.470 --> 03:56.750
in the last video. We had a vector of strings, and we were counting the number of cats in that vector.

03:57.770 --> 04:01.580
So we have a class with a member function, which will do the match() function.

04:03.810 --> 04:08.610
Then we use bind(), with the pointer to this member function as the first argument.

04:09.360 --> 04:13.560
Then we have the address of a object of this class as the second argument.

04:14.520 --> 04:18.540
Then we have a placeholder. That is going to be one of the strings from the vector.

04:19.440 --> 04:21.780
That will be the first argument to this match() call.

04:22.500 --> 04:25.050
And then we bind "cat" as the second argument to

04:25.050 --> 04:26.130
that match() call.

04:28.610 --> 04:29.720
So here is our code again.

04:29.720 --> 04:34.610
We have the same count_strings() function, with the function object as argument.

04:35.330 --> 04:37.280
We have our vector of strings, again.

04:39.640 --> 04:43.570
We have this class, the same as the one on the slide, which will do the comparison.

04:46.000 --> 04:48.070
And then we have our call to bind().

04:48.550 --> 04:50.800
So this is going to return a callable object.

04:51.190 --> 04:58.030
It will call the match() member function on this object, with "cat" as the second argument, and a first

04:58.030 --> 05:00.160
argument which will be provided by the caller.

05:01.150 --> 05:04.120
And then we pass that as the argument to count_strings().

05:05.110 --> 05:11.430
So count_string() will iterate through the vector, and it will call this member function, with each element

05:11.440 --> 05:13.780
of the vector as the first argument.

05:16.190 --> 05:16.760
And there we are.

05:18.740 --> 05:21.050
So when would you use member function pointers?

05:21.650 --> 05:26.120
I have to admit the only time I have ever used them, is in concurrency. In C++,

05:26.660 --> 05:31.460
with threads, you have to put the code for the thread inside a function, and then create a thread object

05:31.760 --> 05:33.860
which has the address of that function.

05:34.490 --> 05:40.160
If you're writing a class which has member functions which run in their own thread, that means you need to pass

05:40.370 --> 05:43.640
member function pointers as arguments to the thread constructor.

05:45.260 --> 05:49.430
You could also use member function pointers for making decisions at runtime.

05:50.030 --> 05:55.760
You could have several objects of the same class, and then you decide which object has the member function

05:55.760 --> 05:56.120
called.

05:56.630 --> 06:03.170
So, for that, you would use bind(). You would bind the arguments to a member function call. You would leave the

06:03.500 --> 06:08.750
object as a placeholder. And then, later on, someone will call this bound function.

06:09.050 --> 06:12.710
They will provide the object they want, and that will call the member function with the arguments.

06:14.370 --> 06:19.580
Or, alternatively, you could have a container of member function pointers, and then you decide which one

06:19.580 --> 06:21.770
of these member functions gets called.

06:22.790 --> 06:28.820
And in both cases, you can use a switch statement, or some if-else branches, to make the actual decision.

06:29.360 --> 06:33.200
So you could use that for implementing state machines, callbacks and so on.

06:33.920 --> 06:35.420
Okay, so that is it for this video.

06:35.780 --> 06:36.620
I will see you next time.

06:36.620 --> 06:38.960
But until then, keep coding!
