WEBVTT

00:00.180 --> 00:03.930
Hello again! In this video, we are going to start looking at virtual functions.

00:04.710 --> 00:10.260
This video is mainly going to be a recap of the previous video, about static and dynamic types.

00:10.710 --> 00:12.330
But we are going to go a little bit further.

00:13.890 --> 00:18.720
I think it is worth spending time making sure that we all understand the concepts, because it can be a

00:18.720 --> 00:21.360
bit hard to grasp at first, if you have not seen it before.

00:22.140 --> 00:29.100
And also every - I think, every - interview that I have had on C++ involved a question on virtual functions.

00:29.460 --> 00:32.040
So it certainly is worth making sure that you understand it.

00:35.380 --> 00:40.600
Normally, when we call a member function, the compiler will decide which function gets called.

00:41.200 --> 00:48.460
So in code like this, if the draw() member function is a normal member function, then the compiler will see that

00:48.460 --> 00:54.400
"rShape" is a reference to a Shape object. And it is going to call the Shape member function, even

00:54.400 --> 00:59.380
though the actual object being referred to is a Circle. So that uses the static type.

00:59.770 --> 01:02.470
And this process is known as "static binding".

01:04.910 --> 01:07.400
There are some cases where the dynamic type is used.

01:07.790 --> 01:10.700
So in that case, the compiler will not make the decision.

01:11.000 --> 01:13.280
It just puts some extra code into the binary.

01:13.940 --> 01:20.600
And then, when the program is run, that code is used to decide which function gets called. And that

01:20.610 --> 01:25.070
will use the dynamic type of the object, and that is known as "dynamic binding".

01:27.480 --> 01:30.420
Dynamic binding can only happen if two conditions are true.

01:30.840 --> 01:37.230
We must be calling a member function through a pointer or a reference to a base class. And usually

01:37.230 --> 01:42.900
the pointer will actually be pointing to a child object, or the reference will be a reference to

01:42.900 --> 01:43.740
a child object.

01:44.460 --> 01:49.020
And also, the member function has to be declared "virtual" in the base class.

01:51.560 --> 01:56.690
To make a function virtual, we put the "virtual" key word before the declaration in the base class, like that.

01:57.800 --> 02:02.900
And then this "virtual" member function will be inherited by all the subclasses of the base.

02:03.140 --> 02:05.180
So that is the children, grandchildren and so on.

02:07.230 --> 02:13.950
If a child class re-implements this virtual function, we say that the child overrides the base

02:13.950 --> 02:14.760
class version.

02:17.210 --> 02:19.580
So we have code like this. We have a Shape

02:20.030 --> 02:23.300
as the base class, with a virtual draw() member function.

02:24.050 --> 02:28.370
We have a Circle, which is the child class, and overrides the draw() member function.

02:30.380 --> 02:36.080
And then, when we call the draw() on a reference to a Shape, which is bound to a Circle object, that

02:36.080 --> 02:40.010
will use dynamic binding, and the Circle version of draw() will be called.

02:44.670 --> 02:50.040
We were talking about having a function which can take any object from a class hierarchy.

02:50.610 --> 02:55.560
If we have to use the static type, then we need to write a separate overload for each possible class.

02:56.160 --> 03:00.390
And if we add another class to the hierarchy, then we need to write another overload.

03:01.610 --> 03:03.890
With virtual functions, this becomes much easier.

03:04.340 --> 03:11.450
We can pass a reference or a pointer to the base class. And then, in the function, if we call the virtual

03:11.450 --> 03:17.120
member function, that will use dynamic binding, and it will call the right version for the actual object

03:17.120 --> 03:17.750
that was passed.

03:18.230 --> 03:24.140
So for example, if we pass a Circle by reference - or we could also pass by address - then this draw() member

03:24.140 --> 03:28.130
function will use dynamic binding, and it will call the Circle version of draw().

03:30.700 --> 03:32.000
So let's try this out.

03:32.080 --> 03:35.980
We have our Shape class, with the virtual draw() member function.

03:36.820 --> 03:42.790
We have the child class, which overrides the draw() member function. And then we have a function which

03:42.790 --> 03:47.170
takes the Shape object by reference, and that is going to use dynamic binding.

03:47.950 --> 03:54.130
So whenever it calls the draw() member function, which was declared virtual in the Shape class, we can

03:54.130 --> 03:59.050
give it any subclass of Shape and it will call the member function of that subclass.

04:01.060 --> 04:01.720
So there you are.

04:01.750 --> 04:08.410
We give it a Circle and it calls the Circle member function. The real advantage of this is if we add another class

04:08.770 --> 04:09.690
to the hierarchy.

04:09.700 --> 04:10.510
So let's do that.

04:12.810 --> 04:17.490
So we have the same code as before, but now we have a Triangle class, which also inherits

04:17.490 --> 04:21.300
from Shape, and overrides the draw() member function.

04:23.530 --> 04:28.450
Then we call the draw_shape() function with the Triangle being passed by reference.

04:28.840 --> 04:34.090
Again, this will use dynamic binding. And this call to the draw() member function will call the Triangle

04:34.090 --> 04:36.460
version of the virtual member function.

04:39.480 --> 04:40.230
So there you are.

04:40.470 --> 04:45.420
We can add a new class and our Shape function still works, even though we did not know about the

04:45.420 --> 04:47.520
Triangle class when we vote this draw_shape().

04:49.500 --> 04:50.970
Okay, so that is it for this video.

04:51.390 --> 04:52.230
I will see you next time.

04:52.470 --> 04:54.330
Until then, keep coding!
