MULTIPLY-DERIVED CLASSES ■ 589 A class can contain not just one but several different base classes. In this case the class is derived from multiple base classes in a process known as multiple inheritance. ᮀ The Multiply-Derived Class MotorHome This class Car is used to represent vehicles and the class Home contains characteristic values for an apartment, such as floor space, number and type of rooms, and typical oper- ations, such as building, selling, or renting. Using these two classes you can then derive the MotorHome class. The opposite page shows the inheritance and definition schemes for the new class. An object of the MotorHome class contains both the members of Car and the members of Home. More specifically, the object contains two base sub-objects of type Car and Home. ᮀ Accessibility of Base Classes Since the MotorHome class has two public base classes, it assumes the public inter- faces of both classes. A MotorHome type object not only allows access to the additional public members but to all the public members of the base classes Car and Home. When defining a multiply-derived class, the accessibility, private, protected, or public, must be defined separately for each base class. The MotorHome class could have the public base class Car and the protected base class Home. Example: class MotorHome:public Car,protected Home { . . . }; If the keyword is omitted, the base class will default to private. Example: class MotorHome : public Car, Home { . . . }; This statement defines the public base class Car and the private base class Home. This makes all the public members in Home private members of the derived class. In multiple inheritance each public base class establishes an is relationship. This is similar to simple inheritance. If the MotorHome class inherits two public base classes, a motor-home is a special kind of motor vehicle and a special kind of home. 590 ■ CHAPTER 27 MULTIPLE INHERITANCE Car Car PassCar Van SUV class SUV : public PassCar, public Van { // Here are additional methods and data members }; ■ MULTIPLE INDIRECT BASE CLASSES The multiple indirect base class Car Definition scheme of class SUV MULTIPLE INDIRECT BASE CLASSES ■ 591 ᮀ Multiple Identical Base Classes When multiply-derived classes are defined, a direct base class cannot be inherited more than once. The following statement Example: class B : public A, public A // Error { . . . }; causes the compiler to issue an error message. A class can be derived from several classes that have a common base class, however. This class is then referred to as a multiple indirect base class. The inheritance graph on the opposite page shows the multiply-derived class SUV, which was derived from the classes PassCar and Van. Both base classes were them- selves derived from the Car class. This makes Car a multiple indirect base class of the SUV class. ᮀ Ambiguity An object of the SUV class thus contains the members of Car twice. Access to members of the Car class results in ambiguity. Example: SUV mySUV(. . .); cout << mySUV.getProd(); // Error Both the base classes PassCar and Van contain a method called getProd(), which they both inherited from the Car class. In this case the compiler cannot decide which method is meant. Ambiguity in the context of multiple inheritance is also possible when several base classes contain members with identical names. If both the Home class and the Car class contain a method called getNr(), the getNr() method cannot be correctly identified in the following statement. Example: MotorHome motorHome( . . .); motorHome.getNr(); To resolve ambiguity of this kind, you can use the scope resolution operator to determine which base class is meant. Example: cout << motorHome.Home::getNr(); cout << mySUV.PassCar::getProd(); The getNr() method in the Home class is called first, followed by the getProd() method inherited by PassCar from the Car class. 592 ■ CHAPTER 27 MULTIPLE INHERITANCE Car PassCar Van SUV class PassCar : public virtual Car { // Here are additional members // of class PassCar }; class Van : public virtual Car { // Here are additional members // of class Van }; ■ VIRTUAL BASE CLASSES The virtual base class Car Definition scheme VIRTUAL BASE CLASSES ■ 593 ᮀ Issues You will not normally want a class created by multiple inheritance to contain multiple instances of an indirect base class. Why should a station wagon contain two versions of the manufacturer’s name or the chassis number for example? So you might be asking yourself whether you can define multiply-derived classes that will contain only one instance of an indirect base class. C++ uses virtual base classes to do this. An object in a multiply-derived class contains only one instance of the members in a virtual base class. The inheritance graph on the opposite page uses the SUV class to illustrate this situation. ᮀ Declaration A direct base class is declared virtual when a derived class is defined. You can use the virtual keyword, which directly precedes the name of the base class. In the definition scheme shown opposite, the Car class becomes the virtual base class of PassCar and Van. However, the fact that the base class Car is virtual has no signifi- cance at this point. A virtual base class takes effect in cases of multiple inheritance. The following defi- nition Example: class SUV : public PassCar, public Van { . . . }; ensures that the SUV class only contains one instance of the virtual base class Car. An object my of the SUV class gets sufficient memory for only one Car class sub-object. More specifically, the statement Example: cout<<"Producer: " << mySUV.getProd(); does not cause ambiguity. The following items are important with respect to virtual base classes: ■ a virtual base class stays virtual even if further derivations are built. Each class derived from PassCar also has the Car class as a virtual base class. ■ you cannot change the declaration of an indirect base class to virtual. You must therefore decide what classes are to be declared virtual when you design the class hierarchy. Later modifications will require modifications to the source code of any derived classes. 594 ■ CHAPTER 27 MULTIPLE INHERITANCE Base1 Base2 Base3 MultiDerived class multiDerived : public Base1, public Base2, public Base3 { // Here are additional data members and methods }; ■ CONSTRUCTOR CALLS ᮀ Building an inheritance graph Class Definition Inheritance graph CONSTRUCTOR CALLS ■ 595 ᮀ Initialization When an object is created in a simply-derived class, the sub-objects of the base classes are created first on all levels of the class hierarchy. The sub-object whose class is nearer to the top of the inheritance graph is created first. The order of the constructor calls is “top down” and follows the inheritance graph. The activation order used for the constructors in simple inheritance has been generalized for multiple inheritance. ᮀ Inheritance Graph Again, the inheritance graph, also called sub-object lattice, has an important job to do. When a derived class is defined, the following rules apply: ■ In cases of multiple inheritance, base classes are entered into the inheritance graph from left to right in the order in which they were stated when the class was defined. The graph opposite illustrates this point. If the class hierarchy does not contain any virtual base classes, the following applies to the activation order of the constructors. ■ The base class constructors are executed first, top-down and from left to right on each level. ■ Finally, the constructor belonging to the current class, which is at the bottom of the inheritance graph, is executed. If we look at the example on the opposite page, this means that the sub-objects of the base classes Base1, Base2, and Base3 are created in this order. Then the constructor of MultiDerived is executed. ᮀ Base Initializers The constructor for the class at the bottom end of the inheritance graph uses base initial- izers to pass the values to the direct and indirect base classes. If the base initializer defini- tion is missing in a constructor definition, the default constructor of the base class is automatically executed. Initial values are thus passed to the base class constructors “bottom up.” 596 ■ CHAPTER 27 MULTIPLE INHERITANCE class SUV : public PassCar, public Van { private: // . . . public: SUV( ) : Car( ) { // Initialize additional data members } void display() const { PassCar::display(); Van::display(); // Output additional data members } }; ■ INITIALIZING VIRTUAL BASE CLASSES Class SUV INITIALIZING VIRTUAL BASE CLASSES ■ 597 ᮀ Constructor Calls in Virtual Base Classes When an object is created for a multiply-derived class, the constructors of the base classes are called first. However, if there is one virtual base class in the class hierarchy, the virtual base class constructor is executed before a constructor of a non-virtual base class is called. The constructors of the virtual base classes are called first, followed by the constructors of non-virtual base classes in the order defined in the inheritance graph. ✓ NOTE The constructor of a virtual base class is called with the arguments stated for the base initializer of the last class to be derived, i.e. class at the bottom end of the inheritance graph. ✓ NOTE The constructor of the virtual base class nearest the top of the inheritance graph is executed first. This does not necessarily mean the top level of the class hierarchy, since a virtual base class can be derived from a non-virtual base class. In our example with the multiply-derived class SUV (Sport Utility Vehicle) the con- structor for the virtual base class Car is called first, followed by the direct base classes PassCar and Van, and last but not least, the constructor of the SUV class. ᮀ Base Initializers You may be wondering what arguments are used to call the constructor of a virtual base class. A base initializer of the directly-derived class or any other derivation could be responsible. The following applies: The example opposite shows SUV containing a constructor with one base initializer. Its arguments are passed to the constructor of the virtual base class Car. For the purpose of initialization, it does not matter whether a class derived directly from Car contains a base initializer or not. Base initializers for virtual indirect base classes defined in the constructor of a direct base class are ignored. If the base classes PassCar and Van also contained base initializers for the virtual base class Car, these would be ignored too. If the constructor for the last derived class does not contain a base initializer, the default constructor is executed for each virtual base class. Whatever happens, a default constructor must then exist in every virtual base class! Thus, base initializers that happen to exist in base classes are also ignored. exercises 598 ■ CHAPTER 27 MULTIPLE INHERITANCE Data member: Type cat CATEGORY Methods: MotorHome(CATEGORY, long, const string&, int, double ); void setCategory(CATEGORY ) CATEGORY getCategory() const ; void display() const; Car Home MotorHome ■ EXERCISES The multiply-derived class MotorHome Additional members of class MotorHome . Car contains a base initializer or not. Base initializers for virtual indirect base classes defined in the constructor of a direct base class are ignored. If the base classes PassCar and Van also. Output additional data members } }; ■ INITIALIZING VIRTUAL BASE CLASSES Class SUV INITIALIZING VIRTUAL BASE CLASSES ■ 597 ᮀ Constructor Calls in Virtual Base Classes When an object is created for a. respect to virtual base classes: ■ a virtual base class stays virtual even if further derivations are built. Each class derived from PassCar also has the Car class as a virtual base class. ■ you cannot