How to determine the type of object (RTTI) of at runtime: NorthTibet
RTTI is an abbreviation of "Runtime Type Information" means: Runtime Type Information. It provides a method for determining an object type at runtime. This article will brief some background knowledge of RTTI, describe the concept of RTTI, and introduce when to use specific example and code, how to use RTTI; this article will also describe the use of two important RTTI operators, they are typeid and Dynamic_cast. In fact, RTTI is not a new thing in C , which has already appeared before more than ten years. But most developers, including many high-level C programmers, not familiar with it, not to mention using RTTI to design and write applications. Some of the object-oriented experts have advocated the use of virtual member functions in design and development, without using the RTTI mechanism. However, in many cases, the virtual function cannot overcome the limitations of itself. Each time to deal with a heterogeneous container and a base class (such as MFC), it is inevitable to dynamically determine the object type, which is the dynamic type detection. How to determine the dynamic type of the object? The answer is the operator in the built-in RTTI: TypeID and Dynamic_cast. Let us first design a class level, suppose we created an abstract base class for a process file. It declares the following pure virtual functions: open (), close (), read (), and write ():
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 destructor (Dtor)
}; Now you have a pure virtual function of the base class from the File class, and some other operations are provided. Assume that derived class is DiskFile, in addition to the pure virtual function of the base class, you must implement your own flush () and defragment () operations:
Class DiskFile: Public File
{
PUBLIC:
INT OPEN (Const string & filename);
/ / Implement additional pure virtual functions
......
// ourselves
Virtual Int flush ();
Virtual int defragment ();
}; Then, also derived two classes from the DiskFile class, assuming TextFile and MediaFile. The former for text files, the latter for audio and video files:
Class textFile: Public Diskfile
{
// ......
INT Sort_BY_WORDS ();
}
Class Mediafile: Public Diskfile
{
// ......
}; We have to create such a class level because it can create a polymorphic object after doing so, such as:
File * pfile; // * Pfile's static type is file
IF (some_condition)
Pfile = new textfile; // Dynamic Type is TextFile
Else
Pfile = new diskfile; // Dynamic Type is DiskFile Suppose You are developing a file manager based on graphical user interface (GUI), each file can be displayed in an icon. When the mouse is moved on the icon and right-click, the File Manager opens a menu, each file is in addition to the common menu item, and the different file types have different menu items. Such as: Common menu items have "Open" "Copy", and "Paste", in addition, there are some special operations for special documents. For example, text files will have "edit" operation, and multimedia files will have the "Play" menu. In order to use RTTI to dynamically customize menu, the file manager must detect dynamic types of each file. Using the operator TypeID to get the runtime type information associated with an object. TYPEID has a parameter, passing an object or type name. Therefore, in order to determine the dynamic type of X, it can be implemented using an expression: typeid (x) == typeid (y): #include
Void Menu :: Build (const file * pfile)
{
IF (TypeId (* pfile) == typeid (TextFile))
{
Add_option ("Edit");
}
Else IF (TypeId (* pfile) == typeid (MediaFile))
{
Add_option ("play");
}
} To pay attention to a problem using TypeID, some compilers (such as Visual C ) The default status is disabled, the purpose is to eliminate overhead on performance. If your program does use RTTI, you must remember to enable RTTI before compiling. Use TypeID to produce some future maintenance issues. Suppose you decide to expand the above level, derive another class named LocalizeMedia from MediaFile, using this class to indicate a media file with different language descriptions. But LocalizeMedia is essentially a MEDIAFILE type of file. Therefore, when the user is right-click on the class file icon, the file manager must provide a "play" menu. Unfortunately, the build () member function will call failed because you didn't check this specific file type. In order to solve this problem, you must make a patch to build () on this below:
Void Menu :: Build (const file * pfile)
{
// ......
Else if (TypeId (* pfile) == TypeId (LocalizedMedia))
{
Add_option ("play");
}
} Oh, this practice is really too amazing. Every time I add a new class, there is no doubt that I have to hit a similar patch. Obviously, this is not an ideal solution. At this time we have to use Dynamic_cast, which is used in the polymorphic program to ensure that the correct conversion occurs during runtime (ie the compiler cannot verify whether the correct conversion occurs). Use it to determine an object is a MediaFile object or its derived class object. Dynamic_cast is often used to convert the down type of the derived class pointer from the polymorphic programming base pointer. It has two parameters: one is the type name; the other is a pointer or reference of a polymorphic object. Its function is to convert objects to target types at runtime and return to Boolean results. That is, if the function succeeds and is dynamic to convert * pfile to MediaFile, the dynamic type of PFile is Mediafile or its derived class. Otherwise, Pfile is other type: void menu :: Build (const file * pfile)
{
IF (Dynamic_Cast
{
// pfile is Mediafile or MediaFile derived LocalizedMedia
Add_option ("play");
}
Else if (Dynamic_cast
{
// Pfile is TextFile is a derived class for TextFile
Add_option ("Edit");
}
}
Think in detail, although using Dynamic_CAST really solves our problems, we also need to pay the price, that is, Dynamic_cast is not a constant time compared to TypeID. In order to determine if the mandatory type conversion can be completed, Dynamic_CAST` must perform some conversion detail operations at runtime. Therefore, when using Dynamic_CAST operation, it should be weighed.
http://www.vckbase.com/document/viewdoc/?id=653