In Chapter 1, we discussed how COM/OLE objects do not support a notion of inheritance, which we defined as a means to achieve polymorphism and reusability. Inheritance is the relationship through which you describe a class as resembling some other more generic class (the base class). When a more specific class is derived from the base class, it inherits the characteristics of that base class. The derived class can then be treated polymorphically with the base class, which is the primary purpose of inheritance. When these ideas are applied to object implementation as well as object definition, you have what is called implementation inheritance.
Implementation inheritance has two significant drawbacks. The first is language dependency, which is not suitable in a language-independent binary component environment such as OLE. The second problem is known as the fragile base class problem, which complicates the evolution of software written with implementation inheritance. This problem occurs when you have a base class B that calls one of its own virtual functions. If you create a derived class D that overrides that virtual function, the implementation of class B used for an instance of class D will now call D's override of the virtual function. This is not, however, the code that B was designed to call. Thus, class B is fragile because the implementation of D's override can easily break B, and the implementer of B has to be extremely careful and usually has to give away the source code to B so that people making derived classes know what B expects. It's also a problem when you have two unrelated pieces of code working on the same object instance and the contracts for communication between base and derived classes are very weak. This again is why base class implementers typically ship source code. Robustness depends a great deal on the discipline of human programmers.
Suffice it to say that this makes a process such as direct implementation inheritance unworkable for large component systems such as those that COM and OLE support, not just because of the fragility of base classes and the language dependence, but also because Microsoft doubts that everyone will want to ship the source code to all of their components to everyone else in the industry. Therefore, we need different component-oriented binary mechanisms to achieve both polymorphism and reusability.