January 01, 2003
Contract Programming and RTTI
How Not to Use RTTI
How Not to Use RTTI
It's no lie that RTTI is an easily-abused feature of C++ -- most texts point out (correctly) that using RTTI to determine an object's specific type is almost always the result of flawed design. As an example, see what happens when one developer (mis)uses RTTI to discover whether an object can be safely deleted:
void DeleteShape(Shape* S)
{
if(dynamic_cast<Triangle*>(S))
delete S;
else if(dynamic_cast<Circle*>(S))
delete S;
else if(dynamic_cast<PageBorder*>(S))
delete S;
else if(dynamic_cast<Ruler*>(S))
return;
else if(dynamic_cast<LayoutGrid*>(S))
return;
}
Note that there are three classes (apparently) that can be deleted, and (maybe) two that can't. Regrettably, this code will compile and work in the short term; I say regrettably because problems will inevitably begin to appear as the program evolves. What happens when a new class is introduced, say,
Ellipse? The code will continue to compile, and the application will continue to run, yet
Ellipse objects won't be deletable unless the developer remembers to go back and modify the implementation of
DeleteShape(). Similarly, what happens when the capabilities of an object change? Suppose a later release of the application does allow the user to delete
Ruler objects -- again, the developer must remember to alter
DeleteShape() to allow it. Conversely, if an object's behavior changes from deletable to non-deletable without a corresponding update to
DeleteShape(), a user may delete an object that they shouldn't have, probably leading to a
segfault at run time. In all of these scenarios, behavioral changes in unknown numbers of objects have to be matched with changes to an otherwise unrelated function -- a serious violation of encapsulation. That ought to be enough to warn you away from this sort of code, but if it isn't, consider that this design cannot accommodate plug-in objects (popular in the graphics world), because the author of
DeleteShape() can't possibly know in advance the type names of every
Shape-derived class that might be written by a third party! Finally, consider that
DeleteShape() is just one function -- if you have to resort to such trickery here, you'll undoubtedly have to do it in myriad other places, adding up to a maintenance nightmare. The moral of the story is that you should never need to use RTTI to find out the actual concrete type of an object at run time -- anytime you're tempted to do so, it's a surefire pointer to problems in the design. You should be testing objects for their capabilities instead of their type, as described in the accompanying article.
Previous Page |
1
|
2