First Time Here

  • June 2020
  • PDF

This document was uploaded by user and they confirmed that they have the permission to share it. If you are author or own the copyright of this book, please report to us by using this DMCA report form. Report DMCA


Overview

Download & View First Time Here as PDF for free.

More details

  • Words: 3,253
  • Pages: 27
First time here? Check out the FAQ!

×

login | about | faq

• • • • •

Questions



Ask Question

Tags Users Badges Unanswered

C++ RTTI Viable Examples

9 6

I am familiar with C++ RTTI, and find the 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(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 boost::any object!

6

This basically uses the RTTI info to store any object and the retrieve that object use boost::any_cast<>. link| flag

answered Oct 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 nonpolymorphic types, to be sure the cast is correct. +1 – paercebal Oct 27 '08 at 10:56

5

Acyclic Visitor (pdf) is a great use of 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

3

I cant say I've ever found a use for in 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(b)) doFoo(b1); else if (B2 *b2=dynamic_cast(b)) doFoo(b2); } }; link|flag

answered Oct 26 '08 at 19:45

1800 INFORMATION 24.1k●2●17●55

2

I worked on an aircraft simulation once, that had 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(char* name="") {

foreach(SimModel* mo in ModelList) if(name == "" || mo->name eq name) { if(dynamic_castmo != NULL) { return dynamic_castmo; } } 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. 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.

2

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

2

Sometimes s ta t i c _casand t C-style 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(p); // Compilation error! //right* r = (right*)p; // Gives bad pointer silently right* r = dynamic_cast(p); // OK

link|flag

answered Oct 27 '08 at 14:51

Motti

5,816●9●36

1

You can use RTTI with 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(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(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

0

I used RTTI when doing some canvasbased 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| flag

answered Oct 26 '08 at 20:35

itsmatt

8,297●12●30

0

I'm using it with 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 Get an OpenID

o r

Name Email never shown Home Page

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 // 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 (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 [email protected].

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! Read a letter from Jimmy Wales and Michael Snow.

[Hide] [Help us with translations!]

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

Related Documents

First Time Here
June 2020 3
Here
June 2020 13