A novice programmer quickly finds that the research battle to understand exception handling in a library is as difficult as the struggle to learn the language itself; modern libraries can contain routines and paradigms as alien and difficult as any C++ syntax detail. Exposure to and understanding of the intricacies of libraries and classes is, for good software, as necessary as the time you spend learning C++ itself. The exception and error-handling details you decipher from your libraries’ documentation and source code will always serve you and your software in good stead.
Runtime Type Identification
What Is RTTI For?
Suppose you have a hierarchy of classes descended from a common base class. You can set a base-class pointer to point to an object of any of the classes in this hierarchy. Next, you call a function that, after processing some information, selects one of these classes, creates an object of that type, and returns its address, which gets assigned to a base-class pointer. How can you tell what kind of object it points to?
Before answering this question, you need to think about why you would want to know the type. Perhaps you want to invoke the correct version of a class method. If that’s the case, you don’t really need to know the object type, as long as that function is a virtual function possessed by all members of the class hierarchy. But it could be that a derived object has an uninherited method. In that case, only some objects could use the method. Or maybe, for debugging purposes, you would like to keep track of which kinds of objects were generated. For these last two cases, RTTI provides an answer.
How Does RTTI Work?
C++ has three components supporting RTTI:
• The dynamic_cast operator generates a pointer to a derived type from a pointer to a base type, if possible. Otherwise, the operator returns 0, the null pointer.
• The typeid operator returns a value identifying the exact type of an object.
• A type_info structure holds information about a particular type.
You can use RTTI only with a class hierarchy that has virtual functions. The reason for this is that these are the only class hierarchies for which you should be assigning the addresses of derived objects to base-class pointers.
Caution
RTTI works only for classes that have virtual functions.
Let’s examine the three components of RTTI.
The dynamic_cast Operator
The dynamic_cast operator is intended to be the most heavily used RTTI component. It doesn’t answer the question of what type of object a pointer points to. Instead, it answers the question of whether you can safely assign the address of an object to a pointer of a particular type. Let’s look at what that means. Suppose you have the following hierarchy:
class Grand { // has virtual methods};
class Superb : public Grand { ... };
class Magnificent : public Superb { ... };
Next, suppose you have the following pointers:
Grand * pg = new Grand;
Grand * ps = new Superb;
Grand * pm = new Magnificent;
Finally, consider the following type casts:
Magnificent * p1 = (Magnificent *) pm; // #1
Magnificent * p2 = (Magnificent *) pg; // #2
Superb * p3 = (Magnificent *) pm; // #3