devxlogo

Use RTTI for Dynamic Type Identification

Use RTTI for Dynamic Type Identification

++ creators introduced Runtime Type Information (RTTI) more than a decade ago. Yet even today many programmers arent fully aware of its benefits and perils. In the following sections, I will show when and how you should use RTTI.



Object-oriented pundits claim that with a proper design and judicious use of virtual member function, you won’t need to use RTTI. However, under certain conditions, for example, when using heterogeneous containers and root-based class hierarchies (MFC for example), dynamic type detection is sometimes unavoidable. How can you detect an objects dynamic type?



Use the built-in RTTI operators typeid and dynamic_cast.Designing a Class Hierarchy
Consider an abstract class that serves as a file interface. It declares the functions open(), close(), read() and write() as pure virtual:

class File{public: virtual int open(const string & filename)=0; virtual int close(const string & filename)=0; // virtual ~File()=0; // remember to add a pure virtual dtor};

Classes derived from File implement the pure virtual functions and provide additional operations. For example, a DiskFile class may add the flush() and defragment() operations:

class DiskFile: public File{public: int open(const string & filename); // implementation of other pure virtual functions // specialized operations virtual int flush(); virtual int defragment();};

You then derive additional classes from DiskFile such as TextFile and MediaFile, for files that contain audio and video clips:

class TextFile: public DiskFile{// int  sort_by_words();};class MediaFile: public DiskFile{//..};

The use of such a hierarchy enables you to create polymorphic objects:

File *pfile; // static type of *pfile is Fileif(some_condition)  pfile = new TextFile; //dynamic type is TextFileelse  pfile = new DiskFile; //dynamic type is DiskFile

Suppose you’re developing a GUI-based file manager that displays files as icons. When you pass your mouse over such an icon and click, the file manager opens a menu that adjusts itself dynamically according to the marked file. The menu lists a set of operations such as “copy”, “paste,” and “open.” In addition, it displays specialized operations for the particular file. Thus, for a text file, it adds the “edit” operation whereas for a multimedia file it displays the “play” operation instead.Using RTTI
To customize the menu dynamically, the file manager has to probe each files dynamic type.

Operator typeid
Operator typeid retrieves the runtime type information associated with a certain object. typeid takes an object or a type name as its argument. Thus, to determine if the dynamic type of x is Y, check whether the expression typeid(x) == typeid(Y) is true:

#include  // needed for typeidvoid menu::build(const File * pfile){ if (typeid(*pfile)==typeid(TextFile)) {  add_option("edit");  } else if (typeid(*pfile)==typeid(MediaFile)) { add_option("play");  }}
TIP: Certain compilers, such as Visual C++, disable RTTI by default to eliminate performance overhead. If your program does use RTTI, remember to enable RTTI before compilation.

The use of typeid might introduce maintenance problems in the future. Suppose you decide to extend the class hierarchy and derive another class from MediaFile called LocalizedMedia that represents a media file with subtitles in various languages. Yet in essence, a LocalizedMedia file is a MediaFile. Therefore, the file manager should display the “play” option when the user right clicks on a LocalizedMedia file. Unfortunately, the build() member function will fail to do so because you didnt include a test for this particular file type. To fix this, you can patch it like this:

void menu::build(const File * pfile){ //..  else if (typeid(*pfile)==typeid(LocalizedMedia)) {  add_option("play");   }}

Alas, this function will have to be patched every time you add a new class. Clearly, this isn’t an ideal solution.

Operator dynamic_cast
You need a way to determine whether a certain object is a MediaFile or any class derived from it. This is exactly what operator dynamic_cast does. dynamic_cast takes two arguments: a type name and a pointer or a reference to a polymorphic object. It attempts to cast at runtime the object to the target type and returns the result. Put differently, if the function succeeds in casting *pfile to MediaFile dynamically, then pfile’s dynamic type is MediaFile or a class derived from it. Otherwise, pfile is a different beast:

void menu::build(const File * pfile){ if (dynamic_cast  (pfile)) {  // pfile is MediaFile or LocalizedMedia  add_option("play");  } else if (dynamic_cast  (pfile)) {  // pfile is a TextFile or a class derived from it  add_option("edit");  }}

Moderation is Advised
Although the use of dynamic_cast solves this problem neatly, it exacts a toll. As opposed to typeid, a dynamic cast isn’t a constant time operation. In order to determine whether the cast can be performed, dynamic_cast must traverse the derivation lattice of its argument at runtime. Therefore, use dynamic_cast judiciously.

devx-admin

Share the Post: