You are here:

C++/What is RTTI?


please explain me Run time type identification.
Also explain me exact difference between Debug and Release.
How we use RTTI in release build?  

The term used in C++ tends to be Run Time Type Information.

C++ is a statically typed language. This means that all type information is known at compile time.

However for certain language features to work a limited amount of information about types is required at runtime. This is the Run Time Type Information or RTTI.

The primary use of RTTI is to allow dynamic_cast to work. Dynamic here is the opposite of static and means at runtime as opposed to static - at compile time. That is, the type conversion is performed at run time and not by the compiler while building an executable. Hence it has a cost each time code that uses a dynamic_cast is executed.

Although dynamic_cast is useful to be sure you have the correct type when, for example, you are passed a base class pointer or reference and you wish to down cast to a pointer or reference to a derived type, the case where you really require dynamic cast is cross casting.

Cross casting only occurs when using multiple inheritance. Here a type can be derived from two or more base classes. A pointer or reference to such a type can be passed around as a pointer or reference to any of these base types. A cross cast is where we have a pointer or reference to an object as one of its bases but we require it to be a derivative of one of the other bases. Converting from one base to another is a cross cast, because we are going across the inheritance graph from one base type to another.

Consider the (simple) situation where the object in question, of type D, is derived from base classes A and B:

    Class A          Class B
       ^---- Class D ----^

We create a D and pass it to some framework function, which requires a pointer to a type derived from base class A. Later it is passed back to our application code as the object associated with some call back - maybe some GUI event like a button press. Note that it is passed back as pointer to base class A. Now we need to pass this object to some other functions that require a pointer to a type derived from class B. Oops we have a D type, which is both an A and a B as it inherits from both, but our reference to it is in the form of a pointer to A. The A class has no relation to the B class. That is A is not a B. Hence we cannot statically cast A to B. We could statically cast the pointer to A to a pointer to D and then cast the pointer to D to a pointer to B - but as in the simple down casting case, how can we be sure the pointer to B is really a D? The dynamic cast uses, at runtime, the RTTI to first check that the pointer to A really can be converted to a pointer to B and then does this conversion. If it cannot then it returns a 0 (null) pointer value. If the types being used are references then it throws a std::bad_cast exception instead (as there are no such things as null references in C++). In our example a failure might occur if say the pointer to A we were handed was no longer pointing to our D object (or the base class A part of it), but to some object of type E derived from A and F because another part of the code registered the E object after our code registered our D object with the framework.

As you might have gathered all down and cross casting using dynamic_cast only generally makes sense if the objects in question are polymorphic - that is the base classes employ virtual functions that are overridden by their derivations to supply specific behaviours. Hence RTTI is _only_ added to functions that contain at least one virtual function. If there are cases in which a class involved in RTTI has no virtual functions then I tend to make the destructor virtual to satisfy this requirement.

Although not a requirement of the C++ standard the other requirement in practice for many compilers is that RTTI is enabled when compiling your code using a compiler switch. This is because RTTI adds overhead to the code in that some additional data is stored for each class (note: for each class not each object). So if you are not using dynamic_cast then it may make sense to turn off RTTI and save some space. The other C++ feature that you can often control in this way is exception handling as this also adds overhead in time and space to programs, however as exceptions are now used by the C++ standard library not using it at all and turning it off is not such an easy option!

RTTI has one feature that at first seems attractive in the form of the std::type_info class and the name function of this class in particular, which is defined in the standard thus:

   namespace std
       class type_info
         virtual ~type_info();
         bool operator==(const type_info& rhs) const;
         bool operator!=(const type_info& rhs) const;
         bool before(const type_info& rhs) const;
         const char* name() const;
         type_info(const type_info& rhs);
         type_info& operator=(const type_info& rhs);

The standard starts out its description of this class like so:

   "Objects of this class effectively store a pointer to a
    name for the type, and an encoded value suitable for
    comparing two types for equality or collating order."

Sounds like we can do some useful work associating names of types with operations on the type and comparing types to see if they are equal or one appears 'before' another.

However the text of the standard goes on to state:

   "The names, encoding rule, and collating sequence for
    types are all unspecified and may differ between programs."

Which basically means that how RTTI and the type_info class are implemented and used is totally up to the compiler writers and therefore they are likely to be quite different between compilers.

In fact taken literally, the names of types returned by the std::type_info::name() function do not have to be unique or even anything at all - the name for all types could simply just be an empty string.

In short, C++ RTTI and type_info are just enough to support its intended use - dynamic_cast - and not much more. It is certainly _not_ the C++ equivalent of reflection and introspection facilities in dynamic execution environments such as Java or .NET.

As to the "exact difference between Debug and Release", well there is no single exact answer. The exact answer will depend on your build requirements, compiler, platform, tools (e.g. debugger) etc.

In general debug builds will not create optimised code (for speed or space) and will include debug symbols and information so that a source debugger such as that included in the Visual Studio IDE or the GNU GDB can be used to debug the code. The machine/assemble code produced by non-optimised code production is generally easy to associated with the lines for code in the source code. The format of the produced debug symbols and information may be selectable (depending on your compiler) and your choice again will be based on circumstances if your debugger states it requires debug information in format X then you choose format X when compiling your code (assuming such as option is available of course), otherwise look for another debugger that supports a format supported by your compiler.

Debug builds will also tend to define pre-processor macro names to activate debug code (e.g. _DEBUG), and not define those intended for release builds (e.g. NDEBUG, which will cause the standard assert macro to be defined to create no code - which is why you should never put code which does useful work in assert macros, it goes away in release builds!).

A release build on the other hand will usually be configured to create optimised code. Which optimisations are used depend on those offered by the compiler and what is deemed important and safe for the application in question (note: sometimes compiler optimisations have bugs or unexpected/undesirable side effects). Debug information will generally be turned off, or at least reduced to a minimum. Release only pre-processor macro names such as NDEBUG will be defined and debug only macro names (e.g. _DEBUG) not defined.

The reasons for these different build settings is due to the differences in intended use.

Debug builds are useful during development where new code has often to be debugged to get the initial problems out, and maintenance, where bug fixing is being done. In this case speed and size are not so important, nor is exposing internal information about the code in the form of debug information to your customers and competitors a problem. Locating and fixing problems as quickly as possible is important.

A release build however is as small and fast as possible (with compiler optimisation options that often allow favouring one over the other), so your product uses as little memory to get as much done as possible. As little information on the original code is shipped to prevent reverse engineering (note: this is a problem for Java and .NET products where you can quite easily get code reversed engineered. IN these cases code obfuscation - usually in the form of running the code through a specific development tool - is often used before releasing an executable to obscure the original names of things in the code).

Note that the nightmare bugs are ones that _only_ appear in release builds as in these cases tedious techniques have to be used to get a build that both exhibits the problem and can shed light on what the cause of the problem is.

As to how you use RTTI in release builds - the same as you do in debug builds. I am confused as to your point here so could you offer more detail on exactly how you are using RTTI so that it only seems necessary in debug builds or what ever you were thinking of please?  


All Answers

Answers by Expert:

Ask Experts


Ralph McArdell


I am a software developer with more than 15 years C++ experience and over 25 years experience developing a wide variety of applications for Windows NT/2000/XP, UNIX, Linux and other platforms. I can help with basic to advanced C++, C (although I do not write just-C much if at all these days so maybe ask in the C section about purely C matters), software development and many platform specific and system development problems.


My career started in the mid 1980s working as a batch process operator for the now defunct Inner London Education Authority, working on Prime mini computers. I then moved into the role of Programmer / Analyst, also on the Primes, then into technical support and finally into the micro computing section, using a variety of 16 and 8 bit machines. Following the demise of the ILEA I worked for a small company, now gone, called Hodos. I worked on a part task train simulator using C and the Intel DVI (Digital Video Interactive) - the hardware based predecessor to Indeo. Other projects included a CGI based train simulator (different goals to the first), and various other projects in C and Visual Basic (er, version 1 that is). When Hodos went into receivership I went freelance and finally managed to start working in C++. I initially had contracts working on train simulators (surprise) and multimedia - I worked on many of the Dorling Kindersley CD-ROM titles and wrote the screensaver games for the Wallace and Gromit Cracking Animator CD. My more recent contracts have been more traditionally IT based, working predominately in C++ on MS Windows NT, 2000. XP, Linux and UN*X. These projects have had wide ranging additional skill sets including system analysis and design, databases and SQL in various guises, C#, client server and remoting, cross porting applications between platforms and various client development processes. I have an interest in the development of the C++ core language and libraries and try to keep up with at least some of the papers on the ISO C++ Standard Committee site at


©2017 All rights reserved.