The C++ Programming Languages(3rd Edition)
Some useful opinions about OOP.
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.
The book explains how derived class is implemented.
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:
 Ensure that only objects of a single type are pointed to.
 Place a type field in the base class for the functions to inspect.
 Use dynamic_cast.
 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 error-prone 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.