Should I use RTTI?

M

mscava

Well I've got a problem, that is more theoretical than practital. I
need to know benefits of RTTI. I see another way of doing it...

class A {
public:
~virtual A() {}

enum Type { X, Y, Z };

Type GetType() { return type_; }

private:
Type type_;
}

class B : public A { ... }

and now if I want to know what type of class it is I just call a
GetType method.

I'd be really pleased with any advice. Thanks.
 
I

Ian Collins

Well I've got a problem, that is more theoretical than practital. I
need to know benefits of RTTI. I see another way of doing it...

class A {
public:
~virtual A() {}

enum Type { X, Y, Z };

Type GetType() { return type_; }

private:
Type type_;
}

class B : public A { ... }

and now if I want to know what type of class it is I just call a
GetType method.

I'd be really pleased with any advice. Thanks.
Perfectly valid for a known set of types.
 
G

Gianni Mariani

Well I've got a problem, that is more theoretical than practital. I
need to know benefits of RTTI. I see another way of doing it...

class A {
public:
~virtual A() {}

enum Type { X, Y, Z };

Type GetType() { return type_; }

private:
Type type_;
}

class B : public A { ... }

and now if I want to know what type of class it is I just call a
GetType method.

Your method requires some type of maintenance by the programmer. The
built-in typeid facility does all the magic for you.

I suppose you could build somthing similar out of templates but then "why" ?
 
S

Salt_Peter

Well I've got a problem, that is more theoretical than practital. I
need to know benefits of RTTI. I see another way of doing it...

class A {
public:
~virtual A() {}

enum Type { X, Y, Z };

Type GetType() { return type_; }

private:
Type type_;
}

class B : public A { ... }

and now if I want to know what type of class it is I just call a
GetType method.

I'd be really pleased with any advice. Thanks.

Is this what you had in mind?

#include <iostream>
#include <ostream>
#include <typeinfo>

template< typename Type >
class A {
Type type;
public:
A() : type() { }
virtual ~A() { }
std::string GetType() const { return typeid(type).name(); }
virtual void foo() const = 0;
};

template< typename T >
class B : public A< T >
{
public:
void foo() const
{
std::cout << "B< " << A<T>::GetType();
std::cout << " >::foo()\n";
}
};

// lets replace X, Y and Z with int, long and std::string for for
illustration.

int main()
{
B< int > bn;
bn.foo();
B< long > bl;
bl.foo();
B< std::string > bs;
bs.foo();
}

/* possible sample output:
B< i >::foo()
B< l >::foo()
B< Ss >::foo()
*/

Then why use RTTI? The only reason i can think for getting the typeid
involved is to break the rules of inheritance. These examples with int,
long and std::string could have been X, Y and Z. If you needed B<
std::string > to call a different foo() than the templated version
provided, specialize the template. Its that simple.

template< >
void B< std::string >::foo() const
{
std::cout << "the member in base is a string.\n";
}

/* result:
B< i >::foo()
B< l >::foo()
the member in base is a string.
*/

You don't need RTTI to do that. There is no need to tell the compiler
which type is involved, it already knows.
 
N

Noah Roberts

Well I've got a problem, that is more theoretical than practital. I
need to know benefits of RTTI. I see another way of doing it...

I am of the opinion that you should disable all possible language
features you can and rewrite them all yourself. Disable RTTI, disable
exceptions, and don't dare use the standard library...especially not
the STL.
 
G

Grizlyk

Well I've got a problem, that is more theoretical than practital. I
need to know benefits of RTTI. I see another way of doing it...

I think, RTTI used for "dynamic_cast<>", not only for "typeid" (at
least for some C++ compiler implementation it is true - "dynamic_cast
.... Note: Runtime type information (RTTI) is required for
dynamic_cast").

If you are using class with multiple inheritance and pointers to its
base classes (for example pointers returned from base classes), you
especially can not avoid "dynamic_cast<>", due to unpredicted "this"
address migration from one base class to another or compiler
limitations.

Consider output

//base pointers are not equal
= Test* new Test(1)
9f640: Class
9f630: Base: data: 1
9f638: Class2
9f630: Test: data: 1
= Class* new Test(0)
9fef0: Class
9fee0: Base: data: 0
9fee8: Class2
9fee0: Test: data: 0

= Test* dynamic_cast<Test*> (Class*) ( from base class to real class
of obj )
9fee0: ok 9fee0=dynamic_cast<Test*>(9fef0)

= return "this" from base class Class
9fee0: 9fee0->test() == 9fef0
* Test* C-style cast<Test*> (Class*) ( from base class to real class
of obj )
error: cannot convert from base 'Class' to derived type 'Test' via
virtual base 'Class'

= return "this" from base class Class2
9fee0: test2() == 9fee8
* Test* C-style cast<Test*> (Class2*) ( from base class to real class
of obj )
9fee0: (C-style cast) from 9fee8

As you see, you can write C-style cast for not virtual base classes,
but for multiple inheritance it will be not only unclear (what the way
compiler will use - reinterpret_cast<> or dynamic_cast<>?), it is very
easy to put wrong data to the class pointer without dynamic_cast<>.
 
C

Craig Scott

Well I've got a problem, that is more theoretical than practital. I
need to know benefits of RTTI. I see another way of doing it...

class A {
public:
~virtual A() {}

enum Type { X, Y, Z };

Type GetType() { return type_; }

private:
Type type_;

}class B : public A { ... }

and now if I want to know what type of class it is I just call a
GetType method.

I'd be really pleased with any advice. Thanks.


Something a little out of left field may be relevant to you here. If
you are using multiple modules in your application (ie building DLL's
or shared libraries), then using RTTI and/or dynamic_cast can be a
little shaky. If two objects of the same type are created in different
modules/DLLs/shared libraries, then it is entirely possible that the
application will see them as two distinct types with different RTTI
id's. Since the standard is silent about situations like this (it says
nothing about multi-module programs), compilers are free to do this and
indeed we have encountered some mainstream compilers which did (eg some
versions of GCC, but later versions have fixed this). A dynamic_cast
can also incorrectly fail if the object was created in a different
module, and again we have observed this in practice too.

So I guess if you are really paranoid, then your home-grown approach
will avoid these problems, but at the cost of a higher maintenance
burden and more fragile code.

For reference, you may also want to check out two other threads related
to the issues above:

http://groups-beta.google.com/group/comp.lang.c++/browse_frm/thread/0b4577aff1feaa6e/?hl=en#

http://groups-beta.google.com/group...e1ec4/ec83565c227fd25b?hl=en#ec83565c227fd25b
 
G

Grizlyk

Craig said:
If two objects of the same type are created in different
modules/DLLs/shared libraries, then it is entirely possible that the
application will see them as two distinct types with different RTTI
id's.

It is not C++ bug. It is compiler bug, it is evidently. RTTI means
"type identification", not RTMI "module identification". If you are
using constant class description (for example, read-only header file
without preprocessor) in each module, any may expect equal runtime
class. In fact, your words mean, that you can not use many C++ features
for the compiler.

There are many other bugs or not complete C++ implementation in
existing compilers.
Since the standard is silent about situations like this (it says
nothing about multi-module programs), compilers are free to do this and
Write to C++ standart org. If it is real trouble and all around do not
understand, it can be corrected.
A dynamic_cast
can also incorrectly fail if the object was created in a different
module

So I guess if you are really paranoid, then your home-grown approach

But it is not easy to understand what do you advise to do instead of
dynamic_cast<>, typeid and try/catch/throw
 
D

Daniel T.

Well I've got a problem, that is more theoretical than practital. I
need to know benefits of RTTI. I see another way of doing it...

class A {
public:
~virtual A() {}

enum Type { X, Y, Z };

Type GetType() { return type_; }

private:
Type type_;
}

class B : public A { ... }

and now if I want to know what type of class it is I just call a
GetType method.

I'd be really pleased with any advice. Thanks.

I suggest you (a) don't use RTTI and (b) don't use the above either.
Such use violates "tell don't ask". The whole point of inheritance is so
you can use an object without knowing its exact type.
 
C

Craig Scott

It is not C++ bug. It is compiler bug, it is evidently. RTTI means
"type identification", not RTMI "module identification". If you are
using constant class description (for example, read-only header file
without preprocessor) in each module, any may expect equal runtime
class.

The C++ standard does not guarantee this (which is my point). In
practical reality, since everyone intuitively expects it, compiler
writers generally try to support it.
In fact, your words mean, that you can not use many C++ features
for the compiler.

You need to choose carefully *how* you use certain features. There is a
lot of very good advice from some very well respected people on these
issues. It would generally be wise to consider their input.
There are many other bugs or not complete C++ implementation in
existing compilers.

Write to C++ standart org. If it is real trouble and all around do not
understand, it can be corrected.

These issues are already well known by the committee and others. There
has been much discussion about a standard C++ ABI, which would go a
long way to resolving most of the issues, but I'm not sure what the
latest is on that front.
But it is not easy to understand what do you advise to do instead of
dynamic_cast<>, typeid and try/catch/throw

You can still use them, just be careful about what you use them on. If
your application uses shared libraries, consider carefully if you can
guarantee that the same compiler will always be used and with the same
settings/flags. If you can and the compiler is a reasonably mainstream
and recent one, then you can most likely use all the above safely even
across module boundaries (but I'm not willing to bet my house on it).

There are alternatives to dynamic_cast and typid (we use one such
alternative, but it is application specific as to what works for you).
If you are *really* keen, go have a look at the internals of Python and
see how they enumerate data types (but it is not for the
faint-hearted!). It isn't C++, but a similar design can be applied
quite nicely if that's what you want.
 
R

Ron Natalie

Well I've got a problem, that is more theoretical than practital. I
need to know benefits of RTTI. I see another way of doing it...
Actually, it's probably a defect in your design if you EVER
have to ask what an object is. If there is behavior that
is dependent on the type of an object, it probably should be
implemented in a virtual method of the class.
 
A

andrewmcdonagh

have to ask what an object is. If there is behavior that
is dependent on the type of an object, it probably should be
implemented in a virtual method of the class.

We aren't alone in this thought.....
From Effective C++, by Scott Meyers :

"Anytime you find yourself writing code of the form "if the object is
of type T1,
then do something, but if it's of type T2, then do something else,"
slap yourself."
 
G

Gianni Mariani

andrewmcdonagh wrote:
....
"Anytime you find yourself writing code of the form "if the object is
of type T1,
then do something, but if it's of type T2, then do something else,"
slap yourself."

What about boost::any ?
 
D

Daniel T.

Gianni Mariani said:
andrewmcdonagh wrote: ...

What about boost::any ?

... you should endeavor to tell objects what you want them to do;
do not ask them questions about their state, make a decision, and
then tell them what to do.

The problem is that, as the caller, you should not be making
decisions based on the state of the called object that result in
you then changing the state of the object. The logic you are
implementing is probably the called object's responsibility, not
yours. For you to make decisions outside the object violates its
encapsulation.
(http://www.pragmaticprogrammer.com/ppllc/papers/1998_05.html)

Asking an object about its state (and asking its type is doing exactly
that) in order to decide how to work with that object violates
encapsulation. Even with boost::any.
 
N

Noah Roberts

Gianni said:
andrewmcdonagh wrote:
...

What about boost::any ?

I don't particularly feel that boost::any is usefull. About the only
use for it might be passing objects through void* and reinterpreted
types.

The ideas behind boost::any are useful though for implementing an
interface for any object that can respond to a given set of functions
but aren't related to each other.

Neither of these cases asks the object for any data about itself.
 
G

Grizlyk

Daniel said:
Asking an object about its state (and asking its type is doing exactly
that) in order to decide how to work with that object violates
encapsulation.

It (and asking its type is doing exactly that - violates encapsulation)
is not true for pointer/reference to polymorphic type especially in
languages with strict type check, as C++. The cause of asking - to get
extended interface of derived via pointer to its base class. Most user
code must _not_ use cast to derived.
 
D

Daniel T.

Grizlyk said:
It (and asking its type is doing exactly that - violates encapsulation)
is not true for pointer/reference to polymorphic type especially in
languages with strict type check, as C++. The cause of asking - to get
extended interface of derived via pointer to its base class. Most user
code must _not_ use cast to derived.

I'm not sure what you are saying here, I will simply say it in code:

void foo( Type& t ) {
SubType* s = dynamic_cast<SubType*>( &t );
if ( s != NULL )
s->callFunc();
}

is no different logically than:

void foo( Type& t ) {
if ( t.isSub() )
t.callFunc();
}

In both cases, you are asking the object about its state, and then
deciding what to do with the object based on the value returned.
 
F

fungus

Daniel said:
>
I'm not sure what you are saying here, I will simply say it in code:

void foo( Type& t ) {
SubType* s = dynamic_cast<SubType*>( &t );
if ( s != NULL )
s->callFunc();
}

is no different logically than:

void foo( Type& t ) {
if ( t.isSub() )
t.callFunc();
}

What if the function "callFunc()" is only defined
in the derived class? You need a pointer to the
derived class in order to call it.


--
<\___/>
/ O O \
\_____/ FTB. For email, remove my socks.


We’re judging how a candidate will handle a nuclear
crisis by how well his staff creates campaign ads.
It’s a completely nonsensical process.
 
T

Tony

Noah Roberts said:
I am of the opinion that you should disable all possible language
features you can and rewrite them all yourself. Disable RTTI, disable
exceptions, and don't dare use the standard library...especially not
the STL.

You're being facetious.

Tony
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top