Micah said:
Because it pretty much always indicates a design flaw. Polymorphism is
the preferred idiom.
I think there are a few cases where trying to avoid dynamic_cast at
all costs becomes counter-productive, and the code would only get uglier.
For example, let's assume you have some kind of primitive manager
which can contain all types of primitives (ie. it contains pointers to
objects derived from some 'Primitive' base class).
For the user to be able to perform some operations to those primitives
when the manager so requests, there are basically two options: The
manager either calls a virtual function defined in the 'Primitive' base
class (which the derived classes can implement), or the manager calls a
callback function given to it by the user, giving this callback function
a reference/pointer to the object (this reference/pointer has to be of
type 'Primitive', of course, because the actual object can be of any type).
The first option would be the nicest, but it becomes awkward in some
cases. For example, if the operation to be performed requires something
the object itself cannot do. This would mean that the object would have
to have a pointer to the actual module which can do that operation, and
it has to call a function through that pointer, and it has to have
permission to do so (the function must be public, or the object must be
a friend of the module).
This also means you can't have pre-made primitives (eg. provided by
the same library which provides the primitive manager) which can simply
be instantiated and given to the manager. At the very least you will
have to create your own class derived from this pre-made primitive, and
in it you will have to implement the store-pointer-call-function
functionality. This may quickly become laborious if you want to use lots
of different pre-made primitives.
The other alternative is to use the callback mechanism and
dynamic_cast, for example like this:
void MyClass::doSomethingToPrimitive(Primitive* p)
{
Circle* c = dynamic_cast<Circle*>(p);
if(c)
{
// Do something to the circle
}
}
Ugly? Maybe. But IMO less ugly, and especially less laborious than the
first option.
The usual reason to avoid dynamic_cast is that it can fail: This
happens if the object behind the pointer is not of the type being casted
to. However, in this case this is not a problem at all, and in fact part
of the very functionality of the system: The dynamic_cast is actually a
"check" to see if the given object was of a certain type (and if it was,
then some operation is done to it).
Sure, with many objects you end up with a large amount of dynamic
casts and if-blocks, but the alternative is not any less laborious. One
could even argue that the alternative is less readable because the
actual functionality is dispersed and not concisely located at one
place. It all depends on the actual situation, I suppose.