I have heard a lot of people say any usage of typeid
is bad design, yet to me it seems like it offers great utility.
The problem isn't with typeid
. The problem is that seeing typeid
would encourage you to write this:
PolymorphicType *pType = ...;
if(typeid(*pType) == typeid(Derived1))
pType->Func1();
else if(typeid(*pType) == typeid(Derived2))
pType->Func2();
else if(typeid(*pType) == typeid(Derived3))
pType->Func3();
This is what we call "really stupid". This is a virtual function call done in about the least reasonable way possible. typeid
has the potential for abuse when used to replace dynamic_cast
and virtual
functions.
This example may sound far-fetched. After all, it's obvious that this is just a virtual call. But bad code often grows from the path of least resistance; all it takes is for one person to do a typeid() == typeid()
, and the seed of this code has begin. In general, if you're directly using typeid
frequently, odds are very good that you're doing something that could be better done with other language constructs.
typeid
is the polymorphic type deduction method of last resort.
Is all usage of typeid
wrong? Of course not. boost::any
wouldn't be possible without it. Well it would be possible, but it wouldn't be any safer than void*
. typeid
is what makes type-safe boost::any
type erasure possible. There are other legitimate uses of it.
But in code-lines-to-use ratio, I would suggest it should be in about one in 10,000 lines of code, at most. Much fewer than that, and you're probably using it wrong.
Is type checking slow?
In general, the main reason to call typeid
is either in templated code (as in boost::any
) or when you're expecting a polymorphic type. If the type is statically determined (ie: a typename or value of a non-polymorphic type is given), then you can expect it to be done at compile-time.
It's polymorphic values you should be concerned about. I've seen a performance test that showed that some typeid
implementations actually walk the class hierarchy, so the time it takes for them to find the type is proportional to the number of classes between the real type and the given type. Every implementation will be different, but that's a pretty good indication that maybe you shouldn't put it in performance-critical code.