Consider the following declarations which make use of the Rectangle and Square classes defined in Program :
Rectangle r (Point (0,0), 5, 10); Square s (Point (0,0), 15);Clearly, the assignment
r = s;is valid because Square is derived from Rectangle. I.e., since a Square is a Rectangle, we may assign s to r.
On the other hand, the assignment
s = r;is not valid because a Rectangle instance is not necessarily a Square.
Consider now the following declarations:
Rectangle& r = *new Square (Point (0,0), 20); Square s;The assignment s=r is still invalid because r is a reference to a Rectangle, and a Rectangle instance is not necessarily a Square, despite the fact that in this case it actually is!
In order to do the assignment, it is necessary to convert the type of r from a reference to a Rectangle to a reference to a Square. This is done in C++ using a cast operator :
s = (Square&) r;However, a conversion like this is unchecked. Neither the compiler nor the run-time system can determine whether r actually refers to a Square.
To determine the actual type of the object to which r refers, we must make use of run-time type information . In C++ every object instance of a class that has virtual functions keeps track of its type. We can test the type of such an object explicitly using the C++ typeid operator like this:
if (typeid (r) == typeid (Square)) s = (Square&) r;This code is type-safe because the cast is only done when the object to which r refers actually is a Square.
C++ also provides a type-safe cast operator called dynamiccast<T>() . In this case, T must either a pointer type or a reference type. The dynamiccast operator combines the run-time type-compatibility check with the type cast operation. For example, the statement
s = dynamic_cast<Square&> (r);succeeds if r is found at run-time to be is an instance of the Square class. If it is not, the dynamiccast operator throws a badcast exception. (Exceptions are discussed in Section ).