1. Run-Time Type Identification
RTTI is provided through two operators:
- The typeid operator, which returns the actual type of the object referred to by a pointer or a reference
- The dynamic_cast operator, which safely converts from a pointer or reference to a base type to a pointer or reference to a derived type
These operators return dynamic type information only for classes with one or more virtual functions
. For all other types, information for the static (i.e., compile-time) type is returned. Dynamic casts should be used with caution. Whenever possible, it is much better to define and use a virtual function rather than to take over managing the types directly.
2. The dynamic_cast Operator
The dynamic_cast operator can be used to convert a reference or pointer to an object of base type to a reference or pointer to another type in the same hierarchy.
Unlike other casts, a dynamic_cast involves a run-time type check. If the object bound to the reference or pointer is not an object of the target type, then the dynamic_cast fails. If an dynamic_cast to a pointer type fails, the result of the dynamic_cast is the value 0. If a dynamic_cast to a reference type fails, then an exception of type bad_cast is thrown. The verification that the dynamic_cast operator performs must be done at run time
.if (Derived *derivedPtr = dynamic_cast<Derived*>(basePtr))
{
// use the Derived object to which derivedPtr points
} else { // BasePtr points at a Base object
// use the Base object to which basePtr points
}
Performing a dynamic_cast in a condition ensures that the cast and test of its result are done in a single expression. Another advantage is that the pointer is not accessible outside the if. If the cast fails, then the unbound pointer is not available for use in later cases where the test might be forgotten.void f(const Base &b)
{
try {
const Derived &d = dynamic_cast<const Derived&>(b);
// use the Derived object to which b referred
} catch (bad_cast) {
// handle the fact that the cast failed
}
}
3. The typeid Operator
typeid(e)
where e is any expression or a type name. When the operand is not of class type or is a class without virtual functions, then the typeid operator indicates the static type of the operand. When the operand has a class-type that defines at least one virtual function, then the type is evaluated at run time. The result of a typeid operation is a reference to an object of a library type named type_info.Base *bp;
Derived *dp;
// compare type at run time of two objects
if (typeid(*bp) == typeid(*dp)) {
// bp and dp point to objects of the same type
}
// test whether run time type is a specific type
if (typeid(*bp) == typeid(Derived)) {
// bp actually points to a Derived
}
Note that the operands to the typeid are expressions that are objectswe tested *bp , not bp. Dynamic type information is returned only if the operand to typeid is an object of a class type with virtual functions. Testing a pointer (as opposed to the object to which the pointer points) returns the static, compile-time type of the pointer.
If the value of a pointer p is 0, then typeid(p) throws a bad_typeid exception if the type of p is a type with virtual functions. If the type of p does not define any virtuals, then the value of p is irrelevant. As when evaluating a sizeof expression the compiler does not evaluate p . It uses the static type of p , which does not require that p itself be a valid pointer.