Hello again! In this video, we are going to look at run-time type information. Run-time type information,
RTTI for short.
As you might guess, this gives us information about types
at run-time.
So that means dynamic types of objects.
There are three features, if you like: the typeid, the type_info and dynamic_cast.
typeid() is a function.
It returns information about the dynamic type of its argument.
It is defined in the typeinfo header, and it is mainly used in comparisons.
So if we have a pointer to base, and we want to know if that object has the same dynamic type as a circle
object, then we can use this to find out.
So we have our Shape hierarchy, with the Circle and Triangle child classes.
We have a Circle and Triangle object, and then we have a pointer to base which is actually pointing
at a Circle object.
So the static type of this is pointer to Shape, and the dynamic type is pointer to Circle.
So, later on in the code, we want to know: does this base plus pointer have the same dynamic type
as a Circle object? So we can call typeid and compare the results to find out.
And yes, pShape does point to a Circle object.
If we change the code,
so this p shape points to a Triangle object, then what do you think will happen?
So we go into the else branch. pShape does not point to a Circle object.
So this comparison returns false,
if pShape is pointing to a Triangle. type_info is a class defined in the header. Note that
the type_info class has an underscore and the header does not.
I am not sure why anyone thought that would be a good idea, but there we are.
When we call typeid, this returns a type_info object.
So type_info contains information about the dynamic type of an object.
It has a member function called name(), which returns a C string.
So you might think that is the name of the class.
In fact, it is the name of the class as used by the compiler.
So it may not necessarily be useful to programmers or end users, but it is unique for each type.
So with the same classes again. This time we keep the returned information from calling typeid().
And.
With Visual C++, we just get the name of the class.
If I compile it with gcc.
Then the result is different.
So we get these strange looking things.
And in fact, that is more typical of the information that you get from calling typeid().
typeinfo also has a hash_code() function.
This will return a number which depends on the dynamic type of its argument.
So this could be used for another way of checking if two objects have the same dynamic type.
And maybe you could use it for doing something clever, like writing your own hash tables, or something
like that.
So again, we have the same classes. We call the typeid(), we get the type_info, and then we
get the hash_code()s for the two objects.
And those are the results with Visual Studio.
Again with GNU C++, we get different results.
And finally, dynamic_cast.
So we can use this to convert a pointer to a base, into a pointer to a derived class object.
And it also applies to references.
So we can convert a reference to base into a reference to derived.
The conversion will only work if the base class is actually pointing, or referring to, a derived class object.
If the conversion fails, the returned point is null, and for references, it throws an exception.
The bad_cast exception from the standard hierarchy.
So we have our pointer to a base class object.
We are going to cast this to a pointer to Circle.
If this fails, the return value will be null.
So we need to check this before we dereference it.
So, in this case, the pointer was pointing to a Circle object.
So that all worked.
If we make it point to a Triangle object...
Then you can probably guess what happens.
The conversion fails, and we go into the else branch, because we got a null pointer.
So it could not cast the Shape.
dynamic_cast is something that you should only use very rarely.
Quite often when people do use it, it is because they do not really understand how inheritance works
in C++.
They think that you have to do dynamic_cast before you can call a member function on the child class, and
that is not correct.
What you should do is write virtual functions in the base class, then override them in the child class,
and then the compiler will do all the work for you.
One situation where it is useful to call dynamic_cast is if you want to call a member function
that is only defined in a derived class.
If you try to call it through pointer to base, or reference to base, the compiler will use the static
type. And it will say that that function is not defined for the base class.
So this is the only way to do it.
So here we have a function which is only defined for the Circle class.
It is not in Shape or Triangle.
This time, we are going to use a reference to the base class. When we call the dynamic_cast,
this will throw an exception if the conversion fails.
So we need to have a try-catch block to handle the exception.
So that succeeds.
pShape is a reference to a Circle object.
So the dynamic_cast has succeeded.
And we could call the member function on the circle object.
If we change this so we now have a Triangle, then we get the exception thrown.
So the dynamic_cast failed and threw an exception.
If you try to call the function directly on this pointer to Circle... (Change that back)
Then that does not compile. "func" is not a member of Shape.
So the compiler will interpret pShape as a reference to the Shape class. And that does not define
this function.
Okay, so that is it for this video.
I will see you next time.
Until then, keep coding!