Let's say I have type A, and a derived type B. When I perform a dynamic cast from A* to B*, what kind of "runtime checks" the environment performs? How does it know that the cast is legal?
I assume that in .Net it's possible to use the attached metadata in the object's header, but what happen in C++?
views:
161answers:
4Dynamic cast performs a runtime check whether this is a valid and doable cast; it'll return NULL when it's not possible to perform the cast.
Dynamic cast is a two-step process:
Given the vtable of a pointer to an object, use the offset to recover a pointer to the full class. (All adjustments will then be made from this pointer.) This is the equivalent of down-casting to the full class.
Search the type_info of the full class for the type we want - in other words, go through a list of all bases. If we find one, use the offset to adjust the pointer again. If the search in step 2 fails, return NULL.
Exact algorithm is compiler-specfic. Here's how it works according to Itanium C++ ABI (2.9.7) standard (written after and followed by GCC).
Pointer to base class is a pointer to the middle of the body of the "big" class. The body of a "big" class is assembled in such a way, that whatever base class your pointer points to, you can uniformly access RTTI for that "big" class, which your "base" class in fact is. This RTTI is a special structure that relates to the "big" class information: of what type it is, what bases it has and at what offsets they are.
In fact, it is the "metadata" of the class, but in more "binary" style.
V instance;
Base *v = &instance;
dynamic_cast<T>(v);
Dynamic cast makes use of the fact that when you write dynamic_cast<T>(v)
, the compiler can immediately identify metadata for the "big" class of v -- i.e. V
! When you write it, you think that T
is more derived than Base
, so compiler will have hard time doing base-to-drived cast. But compiler can immediately (at runtime) determine most deirved type--V
--and it only has then to traverse the inheritance graph contained in metadata to check whether it can downcast V
to T
. If it can, it just checks the offset. If it can't or is amboguous -- returns NULL
.