| < Day Day Up > |
|
Pause here for a moment and consider the multiple inheritance example presented in the previous section. When a derived class object of type HourlyEmployee or SalariedEmployee is created in memory so too are their related base class objects created in memory. Every instance of HourlyEmployee will have its very own Employee and Person base class objects. In the context of the previous example this is exactly the object behavior desired. But what happens when a subclass inherits from two separate classes who themselves inherit from a common base class? You may or may not want multiple copies of the base class created in memory. To control the creation of base classes in a multiple inheritance design you use the virtual keyword to denote virtual inheritance so that only one copy of the base class object is created.
Figure 13-16 shows a class diagram with four classes: A, B, C, & D. Class D inherits from classes B and C.
Figure 13-16: Class Diagram Showing Common Base Class Inheritance
Classes B and C inherit from class A. Using normal, non-virtual inheritance, when a class D object is created, a class B object will be created along with its class A object. A class C object will also be created along with its class A object. This will result in two class A objects existing in memory at the same time as shown in figure 13-17.
Figure 13-17: Non-Virtual Inheritance Will Result in Multiple Instances of Base Classes
In this example, when a D object is created, it would be desirable to have a B and C object created, but not necessarily desirable to have two copies of an A object. (desirability being a matter of design) The non-virtual inheritance implementation of the class diagram shown in figure 13-16 is given in examples 13-29 through 13-33. In these examples I have used inline functions to save space. All the constructors and destructors do is print simple messages so you can trace object creation.
Listing 13.29: a.h
1 #ifndef A_H 2 #define A_H 3 #include <iostream> 4 using namespace std; 5 6 class A { 7 public: 8 A(){cout<<"A constructor"<<endl;} 9 virtual ~A(){cout<<"A destructor"<<endl;} 10 }; 11 #endif
Listing 13.30: b.h
1 #ifndef B_H 2 #define B_H 3 #include "a.h" 4 #include <iostream> 5 using namespace std; 6 7 class B : public A{ 8 public: 9 B(){cout<<"B constructor"<<endl;} 10 virtual ~B(){cout<<"B destructor"<<endl;} 11 }; 12 #endif
Listing 13.31: c.h
1 #ifndef C_H 2 #define C_H 3 #include <iostream> 4 using namespace std; 5 #include "a.h" 6 7 class C : public A{ 8 public: 9 C(){cout<<"C constructor"<<endl;} 10 virtual ~C(){cout<<"C destructor"<<endl;} 11 }; 12 #endif
Listing 13.32: d.h
1 #ifndef D_H 2 #define D_H 3 #include <iostream> 4 using namespace std; 5 #include "b.h" 6 #include "c.h" 7 8 class D : public B, public C { 9 public: 10 D(){cout<<"D constructor"<<endl;} 11 virtual ~D(){cout<<"D destructor"<<endl;} 12 }; 13 #endif
Listing 13.33: main.cpp
1 #include <iostream> 2 #include "d.h" 3 4 int main () { 5 D d; 6 return 0; 7 }
Referring to the code for classes B and C, notice how they publicly inherit from class A in the usual fashion. This is non-virtual inheritance and is the usual form of inheritance you will employ in your design. Class D multiply inherits from class B and C. The creation of a class D object results in an object creation chain reaction as is shown in figure 13-18.
Figure 13-18: Results of Running Example 13.33.
To prevent multiple A instances classes B and C must virtually inherit from A. Only the B and C class declarations need be modified. Examples 13.34 and 13.35 give the modified code.
Example 13.34: b.h
Example 13.35: c.h
Now, when example 13.33 is run again it results in a different output as shown in figure 13-19.
Figure 13-19: Results of Running 13.33 Showing Effects of Virtual Inheritance
Figure 13-20 shows graphically the relationship of A, B, C, and D objects in memory when virtual inheritance is used.
Figure 13-20: Virtual Inheritance Results in One Instance of A
| < Day Day Up > |
|