Re: dynamic_cast is ugly!
On Mar 7, 1:04 am, Juha Nieminen <nos...@thanks.invalid> wrote:
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.
Does the callback really care whether the class of the object (or one
of its base classes) is named "Circle" - or is the callback code more
interested in whether the shape represented by the object - is a
circle (or at least some shape with "circle-like" qualities)?
Almost certainly, the name of the object's class type is not the real
test being applied in the above example. It is easy to image that a
French C++ programmer might decide to name the very same type
differently - "Cercle" perhaps. So in reality, the name of the class
is acting as a kind of proxy for some other aspect or combination of
aspects embodied by the type.
So one of the drawbacks with using dynamic_cast<> and the class name
as a proxy for the properties that actually matter to the call back
routine, is that the dynammic_cast leaves us with little idea what it
is about a circle exactly - that sets it apart from other primitive
types as far as this callback routine is concerned. Whereas, if the
dynamic cast<> were replaced by any of the following member function
calls:
if (p->getNumberOfSides() == 1)
..
if (p->isRound())
or even:
if (p->getShapeType() == kCircleShapeType)
we would have a much better idea what the callback routine is actually
doing with these primitive types. And knowing what a routine is trying
to do goes a long way toward making that routine easy-to-maintain.
Now, calling getShapeType() in the last example might appear to be the
"moral equivalent" to a dynamic_cast<Circle*>. Certainly, the test
being performed is inelegant. Nonetheless, calling a member function
to test for circle types is nonetheless a marked improvement over
calling dynamic_cast<> to do the same.
For one, calling getShapeType() is likely to be much more efficient
than calling dynamic_cast<> (in fact getShapeType() does not
necessarily even have to be a virtual method). Moreover, by using the
class's own interface to distinguish between different types of
objects, we now have a much better understanding of the criteria being
applied. We can conclude from the test for circle type object that the
client requires that the shape not merely be round or one-sided - but
that the object's class type must represent a perfect circle.
Greg