WEBVTT

00:00.150 --> 00:06.630
Hello again! In this video, we are going to look at run-time type information. Run-time type information,

00:06.930 --> 00:08.400
RTTI for short.

00:09.120 --> 00:12.810
As you might guess, this gives us information about types

00:12.810 --> 00:13.650
at run-time.

00:13.890 --> 00:16.290
So that means dynamic types of objects.

00:18.090 --> 00:24.750
There are three features, if you like: the typeid, the type_info and dynamic_cast.

00:26.790 --> 00:28.080
typeid() is a function.

00:28.290 --> 00:31.590
It returns information about the dynamic type of its argument.

00:32.460 --> 00:37.080
It is defined in the typeinfo header, and it is mainly used in comparisons.

00:37.680 --> 00:44.820
So if we have a pointer to base, and we want to know if that object has the same dynamic type as a circle

00:44.820 --> 00:48.420
object, then we can use this to find out.

00:51.390 --> 00:56.370
So we have our Shape hierarchy, with the Circle and Triangle child classes.

00:57.030 --> 01:02.340
We have a Circle and Triangle object, and then we have a pointer to base which is actually pointing

01:02.340 --> 01:03.510
at a Circle object.

01:04.170 --> 01:10.410
So the static type of this is pointer to Shape, and the dynamic type is pointer to Circle.

01:11.520 --> 01:16.740
So, later on in the code, we want to know: does this base plus pointer have the same dynamic type

01:17.040 --> 01:22.080
as a Circle object? So we can call typeid and compare the results to find out.

01:25.030 --> 01:28.030
And yes, pShape does point to a Circle object.

01:30.540 --> 01:31.680
If we change the code,

01:31.770 --> 01:36.630
so this p shape points to a Triangle object, then what do you think will happen?

01:38.980 --> 01:43.060
So we go into the else branch. pShape does not point to a Circle object.

01:43.660 --> 01:45.330
So this comparison returns false,

01:45.340 --> 01:53.260
if pShape is pointing to a Triangle. type_info is a class defined in the <typeinfo> header. Note that

01:53.260 --> 01:57.730
the type_info class has an underscore and the <typeinfo> header does not.

01:58.960 --> 02:01.990
I am not sure why anyone thought that would be a good idea, but there we are.

02:03.130 --> 02:06.970
When we call typeid, this returns a type_info object.

02:07.480 --> 02:12.070
So type_info contains information about the dynamic type of an object.

02:14.020 --> 02:17.980
It has a member function called name(), which returns a C string.

02:18.880 --> 02:20.950
So you might think that is the name of the class.

02:21.220 --> 02:24.430
In fact, it is the name of the class as used by the compiler.

02:24.790 --> 02:31.270
So it may not necessarily be useful to programmers or end users, but it is unique for each type.

02:34.550 --> 02:41.480
So with the same classes again. This time we keep the returned information from calling typeid().

02:45.690 --> 02:46.350
And.

02:50.620 --> 02:53.800
With Visual C++, we just get the name of the class.

02:55.510 --> 02:57.550
If I compile it with gcc.

03:00.580 --> 03:02.230
Then the result is different.

03:02.650 --> 03:04.510
So we get these strange looking things.

03:05.170 --> 03:09.420
And in fact, that is more typical of the information that you get from calling typeid().

03:12.800 --> 03:15.500
typeinfo also has a hash_code() function.

03:16.100 --> 03:19.970
This will return a number which depends on the dynamic type of its argument.

03:20.810 --> 03:25.040
So this could be used for another way of checking if two objects have the same dynamic type.

03:26.120 --> 03:30.920
And maybe you could use it for doing something clever, like writing your own hash tables, or something

03:30.920 --> 03:31.280
like that.

03:34.490 --> 03:43.130
So again, we have the same classes. We call the typeid(), we get the type_info, and then we

03:43.130 --> 03:45.950
get the hash_code()s for the two objects.

03:48.520 --> 03:50.860
And those are the results with Visual Studio.

03:53.590 --> 03:56.920
Again with GNU C++, we get different results.

03:59.660 --> 04:01.460
And finally, dynamic_cast.

04:01.850 --> 04:07.550
So we can use this to convert a pointer to a base, into a pointer to a derived class object.

04:08.270 --> 04:10.100
And it also applies to references.

04:10.460 --> 04:14.300
So we can convert a reference to base into a reference to derived.

04:15.350 --> 04:21.860
The conversion will only work if the base class is actually pointing, or referring to, a derived class object.

04:22.880 --> 04:28.340
If the conversion fails, the returned point is null, and for references, it throws an exception.

04:28.670 --> 04:31.700
The bad_cast exception from the standard hierarchy.

04:34.930 --> 04:37.360
So we have our pointer to a base class object.

04:37.900 --> 04:40.810
We are going to cast this to a pointer to Circle.

04:42.310 --> 04:44.640
If this fails, the return value will be null.

04:44.710 --> 04:47.530
So we need to check this before we dereference it.

04:50.550 --> 04:53.490
So, in this case, the pointer was pointing to a Circle object.

04:53.820 --> 04:54.730
So that all worked.

04:55.410 --> 04:57.630
If we make it point to a Triangle object...

04:59.910 --> 05:01.920
Then you can probably guess what happens.

05:05.400 --> 05:09.330
The conversion fails, and we go into the else branch, because we got a null pointer.

05:09.750 --> 05:11.370
So it could not cast the Shape.

05:13.920 --> 05:17.400
dynamic_cast is something that you should only use very rarely.

05:18.300 --> 05:22.920
Quite often when people do use it, it is because they do not really understand how inheritance works

05:22.920 --> 05:23.760
in C++.

05:24.480 --> 05:30.750
They think that you have to do dynamic_cast before you can call a member function on the child class, and

05:30.750 --> 05:31.470
that is not correct.

05:31.890 --> 05:37.080
What you should do is write virtual functions in the base class, then override them in the child class,

05:37.590 --> 05:39.600
and then the compiler will do all the work for you.

05:41.220 --> 05:46.650
One situation where it is useful to call dynamic_cast is if you want to call a member function

05:46.920 --> 05:49.740
that is only defined in a derived class.

05:51.120 --> 05:55.680
If you try to call it through pointer to base, or reference to base, the compiler will use the static

05:55.680 --> 05:59.340
type. And it will say that that function is not defined for the base class.

05:59.850 --> 06:01.140
So this is the only way to do it.

06:03.060 --> 06:06.990
So here we have a function which is only defined for the Circle class.

06:07.410 --> 06:09.150
It is not in Shape or Triangle.

06:10.530 --> 06:16.620
This time, we are going to use a reference to the base class. When we call the dynamic_cast,

06:16.650 --> 06:18.870
this will throw an exception if the conversion fails.

06:19.230 --> 06:22.860
So we need to have a try-catch block to handle the exception.

06:28.310 --> 06:29.660
So that succeeds.

06:30.980 --> 06:33.980
pShape is a reference to a Circle object.

06:34.250 --> 06:36.260
So the dynamic_cast has succeeded.

06:36.740 --> 06:40.610
And we could call the member function on the circle object.

06:43.660 --> 06:48.460
If we change this so we now have a Triangle, then we get the exception thrown.

06:49.420 --> 06:51.940
So the dynamic_cast failed and threw an exception.

06:58.490 --> 07:04.160
If you try to call the function directly on this pointer to Circle... (Change that back)

07:07.520 --> 07:11.060
Then that does not compile. "func" is not a member of Shape.

07:11.300 --> 07:17.120
So the compiler will interpret pShape as a reference to the Shape class. And that does not define

07:17.120 --> 07:17.690
this function.

07:18.500 --> 07:19.880
Okay, so that is it for this video.

07:20.300 --> 07:21.110
I will see you next time.

07:21.350 --> 07:23.330
Until then, keep coding!
