Although normally you upcast a pointer to a base class and then use the generic interface of that base class (via virtual functions), occasionally you get into a corner where things can be more effective if you know the dynamic type of the object pointed to by a base pointer, and that’s what RTTI provides. The most common misuse may come from the programmer who doesn’t understand virtual functions and uses RTTI to do type-check coding instead. The philosophy of C++ seems to be to provide you with powerful tools and guard for type violations and integrity, but if you want to deliberately misuse or get around a language feature, there’s nothing to stop you. Sometimes a slight burn is the fastest way to gain experience.
Exercises
1. Modify C16:AutoCounter.h in Volume 1 of this series so that it becomes a useful debugging tool. It will be used as a nested member of each class that you are interested in tracing. Turn AutoCounter into a template that takes the class name of the surrounding class as the template argument, and in all the error messages use RTTI to print out the name of the class.
58. Use RTTI to assist in program debugging by printing out the exact name of a template using typeid( ). Instantiate the template for various types and see what the results are.
59. Modify the Instrument hierarchy from Chapter 14 of Volume 1 by first copying Wind5.cpp to a new location. Now add a virtual ClearSpitValve( ) function to the Wind class, and redefine it for all the classes inherited from Wind. Instantiate a TStash to hold Instrument pointers, and fill it with various types of Instrument objects created using the new operator. Now use RTTI to move through the container looking for objects in class Wind, or derived from Wind. Call the ClearSpitValve( ) function for these objects. Notice that it would unpleasantly confuse the Instrument base class if it contained a ClearSpitValve( ) function.
9: Multiple inheritance
The basic concept of multiple inheritance (MI) sounds simple enough: you create a new type by inheriting from more than one base class. The syntax is exactly what you’d expect, and as long as the inheritance diagrams are simple, MI can be simple as well.
Or maybe not! MI can introduce a number of ambiguities and strange situations, which are covered in this chapter. But first, it will be helpful to get a little perspective on the subject.
Perspective
Before C++, the most successful object-oriented language was Smalltalk. Smalltalk was created from the ground up as an object-oriented language. It is often referred to as
Classes in Smalltalk usually have a number of things in common, and they always have
It was not a crystal clear, however, that programmers could not get by without multiple inheritance, and there was (and still is) a lot of disagreement about whether it is really essential in C++. MI was added in AT&T cfront release 2.0 and was the first significant change to the language. Since then, a number of other features have been added (notably templates and exceptions) that change the way we think about programming and place MI in a much less important role. You can think of MI as a "minor" language feature that is seldom involved in your daily design decisions.