Deitel & Associates, Inc. Logo

Back to
digg.png delicious.png blinkit.png furl.png
C++ How to Program, 5/e

© 2005
pages: 1500
Buy the Book!
Amazon logo
InformIT logo

Our C++ Multiple Inheritance tutorial introduced C++'s multiple inheritance capabilities. This tutorial continues our presentation of multiple inheritance by investigating the so-called diamond inheritance problem. We discuss how this problem can be solved with virtual base classes. This tutorial is intended for students and developers who are already familiar with multiple inheritance in C++ or who have read our tutorial on Multiple Inheritance.

Download the code examples for this tutorial.

[Note: This tutorial is an excerpt (Section 24.8) of Chapter 24, Other Topics, from our textbook C++ How to Program, 5/e. These tutorials may refer to other chapters or sections of the book that are not included here. Permission Information: Deitel, Harvey M. and Paul J., C++ HOW TO PROGRAM, ©2005, pp.1218-1222. Electronically reproduced by permission of Pearson Education, Inc., Upper Saddle River, New Jersey.]

24.8 Multiple Inheritance and virtual Base Classes

In Section 24.7, we discussed multiple inheritance, the process by which one class inherits from two or more classes. Multiple inheritance is used, for example, in the C++ standard library to form class basic_iostream (Fig. 24.12).
figure 24.12

Fig. 24.12 Multiple inheritance to form class basic_iostream. Class basic_ios is the base class for both basic_istream and basic_ostream, each of which is formed with single inheritance. Class basic_iostream inherits from both basic_istream and basic_ostream. This enables objects of class basic_iostream to provide the functionality of both basic_istreams and basic_ostreams. In multiple-inheritance hierarchies, the situation described in Fig. 24.12 is referred to as diamond inheritance. Because classes basic_istream and basic_ostream each inherit from basic_ios, a potential problem exists for basic_iostream. Class basic_iostream could contain two copies of the members of class basic_ios—one inherited via class basic_istream and one inherited via class basic_ostream). Such a situation would be ambiguous and would result in a compilation error, because the compiler would not know which version of the members from class basic_ios to use. Of course, basic_iostream does not really suffer from the problem we mentioned. In this section, you will see how using virtual base classes solves the problem of inheriting duplicate copies of an indirect base class.

Compilation Errors Produced When Ambiguity Arises in Diamond Inheritance

Figure 24.13 demonstrates the ambiguity that can occur in diamond inheritance. The program defines class Base (lines 9–13), which contains pure virtual function print (line 12). Classes DerivedOne (lines 16–24) and DerivedTwo (lines 27–35) each publicly inherit from class Base and override the print function. Class DerivedOne and class DerivedTwo each contain what the C++ standard refers to as a base-class subobject—i.e., the members of class Base in this example.

 1  // Fig. 24.13: fig24_13.cpp
 2  // Attempting to polymorphically call a function that is
 3  // multiply inherited from two base classes.
 4  #include <iostream>
 5  using std::cout;
 6  using std::endl;
 8  // class Base definition
 9  class Base
10  {
11  public:
12     virtual void print() const = 0; // pure virtual
13  }; // end class Base
15  // class DerivedOne definition
16  class DerivedOne : public Base
17  {
18  public:
19     // override print function
20     void print() const
21     {
22        cout << "DerivedOne\n";
23     } // end function print
24  }; // end class DerivedOne
26  // class DerivedTwo definition
27  class DerivedTwo : public Base
28  {
29  public:
30     // override print function
31     void print() const
32     {
33        cout << "DerivedTwo\n";
34     } // end function print
35  }; // end class DerivedTwo
37  // class Multiple definition
38  class Multiple : public DerivedOne, public DerivedTwo
39  {
40  public:
41     // qualify which version of function print
42     void print() const
43     {
44        DerivedTwo::print();
45     } // end function print
46  }; // end class Multiple
48  int main()
49  {
50     Multiple both; // instantiate Multiple object
51     DerivedOne one; // instantiate DerivedOne object
52     DerivedTwo two; // instantiate DerivedTwo object
53     Base *array[ 3 ]; // create array of base-class pointers
55     array[ 0 ] = &both; // ERROR--ambiguous
56     array[ 1 ] = &one;
57     array[ 2 ] = &two;
59     // polymorphically invoke print
60     for ( int i = 0; i < 3; i++ )
61        array[ i ] -> print();
63     return 0;
64  } // end main
 Fig. 24.13  Attempting to call a multiply inherited function polymorphically.


 C:\Projects\cpphtp5\examples\ch24\Fig24_20\Fig24_20.cpp(55): error C2594:
 '=' : ambiguous conversions from 'Multiple *' to 'Base *'

Class Multiple (lines 38–46) inherits from both classes DerivedOne and DerivedTwo. In class Multiple, function print is overridden to call DerivedTwo’s print (line 44). Notice that we must qualify the print call with the class name DerivedTwo to specify which version of print to call.

Function main (lines 48–64) declares objects of classes Multiple (line 50), DerivedOne (line 51) and DerivedTwo (line 52). Line 53 declares an array of Base * pointers. Each array element is initialized with the address of an object (lines 55–57). An error occurs when the address of both—an object of class Multiple—is assigned to array[ 0 ]. The object both actually contains two subobjects of type Base, so the compiler does not know which subobject the pointer array[ 0 ] should point to, and it generates a compilation error indicating an ambiguous conversion.
Additional Pages in this Tutorial:   Page 1 | 2

Other tutorials on this topicl:
24.7 Multiple Inheritance
24.8 Multiple Inheritance and virtual Base Classes (You are here).

Tutorial Index