You are on page 1of 27

First time here? Check out the FAQ!

×
login | about | faq

• Questions
• Tags
• Users
• Badges
• Unanswered

• Ask Question

C++ RTTI Viable Examples

I am familiar with C++


9 RTTI, and find the
6 concept interesting.

Still there exist a lot of


more ways to abuse it
than to use it correctly
(the RTTI-switch dread
comes to mind). As a
developer, I found (and
used) only two viable
uses for it (more exactly,
one and a half).

Could you share some


of the ways RTTI is a
viable solution to a
problem, with example
code/pseudo-code
included?

Note: The aim is to have


a repository of viable
examples a junior
developer can consult,
criticize and learn from.

Edit: You'll find below


code using C++ RTTI

// A has a virtual
destructor (i.e. is
polymorphic)
// B has a virtual
destructor (i.e. is
polymorphic)
// B does (or does
not ... pick your
poison) inherits
from A

void

doSomething(A *
{
//
t ype id ( ) : : name( )
re tu rns the
"name" o f the
std::cout <<

"a is [" <<

typeid(*a).name()

/ / the
dynamic_cas t o f a
po in te r t o
another will

return NULL is

// the

conversion is not

possible

if(B * b =

dynamic_cast<B

*>(a))

std::cout

<< "a is b" <<

std::endl ;

else

std::cout

<< "a is NOT b"

<< std::endl ;

c++ rtti design polls


flag edited asked Oct 26
Oct '08 at 18:58
26
'08 at
19:43 paercebal
7,621●12●46

30% accept
rate
You could start by
posting your 1.5
examples. – Ben Collins
Oct 26 '08 at 19:00

The problem is that if I


post them, and they are
the easiest examples
(as I guess they are),
then most people won't
even try sharing their
own. Of course, I'll post
them if no one thought
about them. – paercebal
Oct 26 '08 at 19:08

:-D ... No, I'm not. Ok,


the first is contract
programming, where
you ask an object if he
implements some
interface. If yes, you
then use the inferface.
The second is used
when you have complex
class hierarchy, and
don't want your base
Object class to
implement the method
draw from Shape...
– paercebal Oct 26 '08
at 19:41

1 I can agree with. 2


sounds like a broken
hierarchy. – fizzer Oct
26 '08 at 19:47

The "2" is the .5 part... :-


D ... It's not as much
broken as it is
extended. If you have a
large framework of very
different objects, the
last thing you want is to
have all objects have
the same 3000
methods. So you set
9 Answers
oldest newest votes
How about the
6 boost::any object!

This basically uses the


RTTI info to store any
object and the retrieve
that object use
boost::any_cast<>.

link| answered Oct


flag 26 '08 at 21:11

Martin York
21k●1●18●6
4

While boost:any does


not use dynamic cast,
it uses the typeid
operator which works
even for non-
polymorphic types, to
be sure the cast is
correct. +1
– paercebal Oct 27
'08 at 10:56

Acyclic Visitor (pdf) is a great use of


5 it.

link|flag answered
Oct 26 '08 at
19:40

fizzer
3,172●4●22
I agree. This again what I called
above the "contract" programming.
+1 – paercebal Oct 26 '08 at 20:17

I cant say I've ever found a use for in


3 in real life but RTTI is mentioned in
Effective C++ as a possible solution
to multi-methods in C++. This is
because method dispatch is done on
the dynamic type of the th i s
parameter but the static type of the
arguments.

class base

void foo(base *b) = 0;

// dynamic on the

parameter type as well

};

class B : public base

{...}

class B1 : public B {...}

class B2 : public B {...}

class A : public base

void foo(base *b)


{

if (B1

*b1=dynamic_cast<B1*>(b))

doFoo(b1);

else if (B2

*b2=dynamic_cast<B2*>(b))

doFoo(b2);

};

link|flag answered Oct 26


'08 at 19:45

1800
INFORMATION
24.1k●2●17●55

I worked on an aircraft simulation once, that had


2 what they (somewhat confusingly) referred to as a
"Simulation Database". You could register variables
like floats or ints or strings in it, and people could
search for them by name, and pull out a reference to
them. You could also register a model (an object of a
class descended from "SimModel"). The way I used
RTTI, was to make it so you could search for models
that implement a given interface:

SimModel*

SimDatabase::FindModel<type*>(char*

name="")

{
foreach(SimModel* mo in

ModelList)

if(name == "" || mo->name eq

name)

if(dynamic_cast<type*>mo !=

NULL)

return

dynamic_cast<type*>mo;

return NULL;

The SimModel base class:

class public SimModel

public:

void RunModel()=0;

};
An example interface might be "EngineModel":

class EngineModelInterface : public

SimModel

public:

float RPM()=0;

float FuelFlow()=0;

void SetThrottle(float

setting)=0;

};

Now, to make a Lycoming and Continental engine:

class LycomingIO540 : public

EngineModelInterface

public:

float RPM()

return rpm;

float FuelFlow()
{

return throttleSetting *

10.0;

void SetThrottle(float

setting)

throttleSetting =

setting

void RunModel() // from

SimModel base class

if(throttleSetting >

0.5)

rpm += 1;

else

rpm -= 1;

private:

float rpm, throttleSetting;


};

class Continental350: public

EngineModelInterface

public:

float RPM()

return rand();

float FuelFlow()

return rand;

void SetThrottle(float

setting)

void RunModel() // from

SimModel base class

}
};

Now, here's some code where somebody wants an


engine:

EngineModelInterface * eng =

simDB.FindModel<EngineModelInterface

*>();

fuel = fuel - deltaTime * eng-

>FuelFlow();

Code is pretty pseudo, but I hope it gets the idea


across. One developer can write code that depends
on having an Engine, but as long as it has something
that implements the engine interface, it doesn't care
what it is. So the code that updates the amount of
fuel in the tanks is completely decoupled from
everything except the FindModel<>() function, and
the pure virtual EngineModel interface that he's
interested in using. Somebody a year later can make
a new engine model, register it with the
SimulationDatabase, and the guy above who
updates fuel will start using it automatically. I actually
made it so you could load new models as plugins
(DLLs) at runtime, and once they are registered in
the SimulationDatabase, they could be found with
FindModel<>(), even though the code that was
looking for them was compiled and built into a DLL
months before the new DLL existed. You could also
add new Interfaces that derive from SimModel, with
something that implements them in one DLL,
something that searches for them in another DLL,
and once you load both DLLs, one can do a
FindModel<>() to get the model in the other. Even
though the Interface itself didn't even exist when the
main app was built.

Parenthetically, RTTI doesn't always work across


DLL boundaries. Since I was using Qt anyway, I
used qob jec t _casinstead
t of dynamic_cas t.
Every class had to inherit from QObject (and get
moc'd), but the qobject meta-data was always
available. If you don't care about DLLs, or you are
using a toolchain where RTTI does work across DLL
boundaries (type comparisons based on string
comparisons instead of hashes or whatever), then all
of the above with dynamic_cast will work just fine.

link|flag answered
Oct 26 '08 at
19:50

keysersoze
1,158●2●10
Effectively, I tried, too, the decoupling of interfaces
and implementations, and code using defined
interfaces worked quite well with implementation
types coded time after, without needing
recompilation... +1 – paercebal Oct 26 '08 at 20:05

After reading the first lines of Your post, I wondered


why I could not remember posting some details
about my aircraft simulation. :-D This should proove,
that there are some examples of useful RTTI.
– Black Oct 26 '08 at 20:30
I use it in a class tree which serializes to a XML file.
2 On the de-serialization, the parser class returns a
pointer to the base class which has a enumeration
for the type of the subclass (because you don't know
which type it is until you parse it). If the code using
the object needs to reference subclass specific
elements, it switches on the enum value and
dynamic_cast's to the subclass (which was created
by the parser). This way the code can check to
ensure that the parser didn't have an error and a
mismatch between the enum value and the class
instance type returned. Virtual functions are also not
sufficient because you might have subclass specific
data you need to get to.

This is just one example of where RTTI could be


useful; it's perhaps not the most elegant way to solve
the problem, but using RTTI makes the application
more robust when using this pattern.

link|flag answered
Oct 27 '08 at
2:22

Nick
3,029●2●13
You're right: This is an awful switch/RTTI
combination, but then, you are using XML, and this
is a good solution to strong-type again what was a
string XML <element /> into a full fledged object. +1.
– paercebal Oct 27 '08 at 10:32

Sometimes s ta t i c _casand
t C-style
2 casts just aren't enough and you
need dynamic_cas t, an example
of this is when you have the
dreaded diamond shaped hierarchy
(image from Wikipedia).
struct top {

};

struct left : top {

int i;

left() : i(42)

{}

};

struct right : top {

std::string

name;

right() :
name("plonk") { }

};

struct bottom : left,

right {

};

bottom b;

left* p = &b;

//right* r =

static_cast<right*>(p);

// Compilation error!

//right* r = (right*)p;

// Gives

bad pointer silently

right* r =

dynamic_cast<right*>(p);

// OK
link|flag answered
Oct 27 '08 at
14:51

Motti
5,816●9●36

You can use RTTI with


1 dynamic_cast to get a pointer to a
derived class in order to use it to
call a fast, type specialized
algorithm. And instead of using the
virtual methods through the base
class, it will make direct and inlined
calls.

This sped things up for me a lot


using GCC. Visual Studio didn't
seem to do as well, it may have a
slower dynamic_cast lookup.

Example:

D* obj =

dynamic_cast<D*>(base);

if (obj) {

for(unsigned i=0;

i<1000; ++i)

f(obj-

>D::key(i));

} else {

for(unsigned i=0;
i<1000; ++i)

f(base->key(i);

link|flag edited answered Oct


Oct 26 '08 at
27 21:47
'08 at
16:15
Zan Lynx
3,169●4●16
Probably D* d =
dynamic_cast<D*>(base); for
(i=0;i!=1000;++i) { d->Foo(); }.
Wrong idea, since this doesn't call
MoreDerived::Foo – MSalters Oct
27 '08 at 15:07

Use the d->D::Foo() syntax. I put it


in the example I added. – Zan
Lynx Oct 27 '08 at 16:16

Interesting micro optimization, I'll


have to remember this. – Mark
Ransom Oct 27 '08 at 16:28

I used RTTI when


0 doing some canvas-
based work with Qt
several years ago. It
was darn convenient
when doing hit-tests
on objects to employ
RTTI to determine
what I was going to do
with the shape I'd 'hit'.
But I haven't used it
otherwise in
production code.
link| answered Oct
flag 26 '08 at
20:35

itsmatt
8,297●12●30

I'm using it with


0 Dynamic Double
Dispatch and
Templates. Basically,
it gives the ability to
observe/listen to only
the interesting parts of
an object.

link|flag answered
Oct 27 '08
at 7:47

Johann
Gerell
1,482●1●9

Your Answer


community wiki
OpenID Login o
Name Email never shown Home Page
Get an OpenID r

Not the answer you're looking for? Browse other questions tagged
c++ rtti design polls or ask your own question.

Hello World!

Stack Overflow is a collaboratively edited question and answer site for programmers – regardless
of platform or language. It's 100% free, no registration required.

about » faq »

tagged
c++ × 14361
design × 2023
polls × 585
rtti × 36
asked
11 months ago
viewed
2,103 times
latest activity
11 months ago
Wanted: IT Technologist at Space Telescope Science Institute (Baltimore, MD 21218). See this
and other great job listings at jobs.stackoverflow.com.

Related
To RTTI or not RTTI…
On how many multiple projects do you work?
What field of software engineering do you work in?
Poll: Does your CTO actually Code?
Mixing RTTI flags in C++
How expensive is RTTI?
Is it allowed to link rtti enabled DLL within rtti disabled application?
How do I access Delphi Array Properties using RTTI
How can I assign an interface variable to a variable of type Rtti.TValue
Qt RTTI trouble
How to set event handlers via new RTTI? [D2010]
What’s a good way to serialize Delphi object tree to XML--using RTTI and not custom code?
How to call GetEnumerator on arbitrary type?
Delphi call method based on RTTI information
What is the simplest RTTI implementation for C++?
C++ RTTI Inheritance causes class size to increase
Delphi OTA and RTTI bug
Extract C++ template parameters
How to check if a Delphi class is declared abstract?

question feed

about | faq | blog | podcast | privacy policy | advertising info | contact us | feedback always welcome

■ stackoverflow.com ■ serverfault.com ■ superuser.com ■ meta howtogeek.com doctype.com

svn revision: 4599


site design and logo is © 2009 stackoverflow.com llc; user contributed content licensed under cc-wiki
with attribution required
Stack Overflow works best with JavaScript enabled
http://www.devx.com
Printed from http://www.devx.com/getHelpOn/Article/10202/1954

Use RTTI for Dynamic Type Identification

Runtime Type Information (RTTI) was created more than a decade ago, yet most
developers remain unaware of its functions and benefits. This month's solution
explains when and how you can use RTTI for dynamic type detection.
by Danny Kalev

++ 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 File

if(some_condition)

pfile = new TextFile; //dynamic type is TextFile

else
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 <typeinfo> // needed for typeid

void 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 <MediaFile *> (pfile))

// pfile is MediaFile or LocalizedMedia

add_option("play");

else if (dynamic_cast <TextFile*> (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.
Danny Kalev is a system analyst and software engineer with 13 years of experience, specializing in C++
and object-oriented analysis and design. He was a member of the ANSI C++ standardization committee
between 1997-2001. Danny is the author of ANSI/ISO C++ Professional Programmer's Handbook (Que,
1999, ISBN: 0789720221). Check out the DevX review here. He can be reached at dannykk@inter.net.il.

DevX is a division of Jupitermedia Corporation


© Copyright 2007 Jupitermedia Corporation. All Rights Reserved. Legal Notices

Help build the future of Wikibooks and its


sister projects! [Hide] [Help us with
Read a letter from Jimmy Wales and Michael translations!]

Snow.

C++ Programming/RTTI
From Wikibooks, the open-content textbooks collection
< C++ Programming
Jump to: navigation, search
Contents
[hide]

• 1 Run-Time Type Information (RTTI)


o 1.1 dynamic_cast
o 1.2 typeid
o 1.3 Limitations

o 1.4 Misuses of RTTI

[edit] Run-Time Type Information (RTTI)


RTTI refers to the ability of the system to report on the dynamic type of an object and to
provide information about that type at runtime (as opposed to at compile time).

[edit] dynamic_cast

You might also like