The C++ Programming Languages (3rd Edition)

you can write structured programs
in Fortran77 and object-oriented programs in C, but it is unnecessarily hard to do so because these
languages do not directly support those techniques
In some areas, such as interactive
graphics, there is clearly enormous scope for object-oriented programming. In other areas, such as
classical arithmetic types and computations based on them, there appears to be hardly any scope for
more than data abstraction, and the facilities needed for the support of object-oriented programming
seem unnecessary.
12.2.5 Type Fields [derived.typefield]

To use derived classes as more than a convenient shorthand in declarations, we must solve the following
problem: Given a pointer of type base *, to which derived type does the object pointed to
really belong? There are four fundamental solutions to the problem:
[1] Ensure that only objects of a single type are pointed to.
[2] Place a type field in the base class for the functions to inspect.
[3] Use dynamic_cast.
[4] Use virtual functions.
Pointers to base classes are commonly used in the design of container classes such as set, vector,
and list. In this case, solution 1 yields homogeneous lists, that is, lists of objects of the same type.
Solutions 2, 3, and 4 can be used to build heterogeneous lists, that is, lists of (pointers to) objects of
several different types. Solution 3 is a language-supported variant of solution 2. Solution 4 is a special type-safe
variation of solution 2. Combinations of solutions 1 and 4 are particularly interesting
and powerful; in almost all situations, they yield cleaner code than do solutions 2 and 3.
In other words, use of a type field is an errorprone
technique that leads to maintenance problems.
The problems increase in severity as the size of the program increases because the use of a
type field causes a violation of the ideals of modularity and data hiding. Each function using a type
field must know about the representation and other details of the implementation of every class
derived from the one containing the type field.
It also seems that the existence of any common data accessible from every derived class, such
as a type field, tempts people to add more such data. The common base thus becomes the repository
of all kinds of "useful information." This, in turn, gets the implementation of the base and
derived classes intertwined in ways that are most undesirable. For clean design and simpler maintenance,
we want to keep separate issues separate and avoid mutual dependencies.