The example in Fig. 12.1 reuses the final versions of classes CommissionEmployee
and BasePlusCommissionEmployee
from Section 11.3.5. The example demonstrates three ways to aim base- and derived-class pointers at base- and derived-class objects. The first two are natural and straightforward—we aim a base-class pointer at a base-class object and invoke base-class functionality, and we aim a derived-class pointer at a derived-class object and invoke derived-class functionality. Then, we demonstrate the relationship between derived classes and base classes (i.e., the is-a relationship of inheritance) by aiming a base-class pointer at a derived-class object and showing that the base-class functionality is indeed available in the derived-class object.
1 // Fig. 12.1: fig12_01.cpp
2 // Aiming base-class and derived-class pointers at base-class
3 // and derived-class objects, respectively.
4 #include <iostream>
5 #include <iomanip>
6 #include "CommissionEmployee.h"
7 #include "BasePlusCommissionEmployee.h"
8 using namespace std;
9
10 int main()
11 {
12 // create base-class object
13 CommissionEmployee commissionEmployee(
14 "Sue", "Jones", "222-22-2222", 10000, .06 );
15
16 // create base-class pointer
17 CommissionEmployee *commissionEmployeePtr = nullptr;
18
19 // create derived-class object
20 BasePlusCommissionEmployee basePlusCommissionEmployee(
21 "Bob", "Lewis", "333-33-3333", 5000, .04, 300 );
22
23 // create derived-class pointer
24 BasePlusCommissionEmployee *basePlusCommissionEmployeePtr = nullptr;
25
26 // set floating-point output formatting
27 cout << fixed << setprecision( 2 );
28
29 // output objects commissionEmployee and basePlusCommissionEmployee
30 cout << "Print base-class and derived-class objects:
";
31 commissionEmployee.print(); // invokes base-class print
32 cout << "
";
33 basePlusCommissionEmployee.print(); // invokes derived-class print
34
35 // aim base-class pointer at base-class object and print
36 commissionEmployeePtr = &commissionEmployee; // perfectly natural
37 cout << "
Calling print with base-class pointer to "
38 << "
base-class object invokes base-class print function:
";
39 commissionEmployeePtr->print(); // invokes base-class print
40
41 // aim derived-class pointer at derived-class object and print
42 basePlusCommissionEmployeePtr = &basePlusCommissionEmployee; // natural
43 cout << "
Calling print with derived-class pointer to "
44 << "
derived-class object invokes derived-class "
45 << "print function:
";
46 basePlusCommissionEmployeePtr->print(); // invokes derived-class print
47
48 // aim base-class pointer at derived-class object and print
49 commissionEmployeePtr = &basePlusCommissionEmployee;
50 cout << "
Calling print with base-class pointer to "
51 << "derived-class object
invokes base-class print "
52 << "function on that derived-class object:
";
53 commissionEmployeePtr->print(); // invokes base-class print
54 cout << endl;
55 } // end main
Recall that each BasePlusCommissionEmployee
object is a CommissionEmployee
that also has a base salary. Class BasePlusCommissionEmployee
’s earnings
member function (lines 34–37 of Fig. 11.15) redefines class CommissionEmployee
’s earnings
member function (lines 85–88 of Fig. 11.14) to include the object’s base salary. Class BasePlusCommissionEmployee
’s print
member function (lines 40–48 of Fig. 11.15) redefines class CommissionEmployee
’s version
(lines 91–98 of Fig. 11.14) to display the same information plus the employee’s base salary.
In Fig. 12.1, lines 13–14 create a CommissionEmployee
object and line 17 creates a pointer to a CommissionEmployee
object; lines 20–21 create a BasePlusCommissionEmployee
object and line 24 creates a pointer to a BasePlusCommissionEmployee
object. Lines 31 and 33 use each object’s name to invoke its print
member function.
Line 36 assigns the address of base-class object commissionEmployee
to base-class pointer commissionEmployeePtr
, which line 39 uses to invoke member function print
on that CommissionEmployee
object. This invokes the version of print
defined in base class CommissionEmployee
.
Similarly, line 42 assigns the address of derived-class object basePlusCommissionEmployee
to derived-class pointer basePlusCommissionEmployeePtr
, which line 46 uses to invoke member function print
on that BasePlusCommissionEmployee
object. This invokes the version of print
defined in derived class BasePlusCommissionEmployee
.
Line 49 then assigns the address of derived-class object basePlusCommissionEmployee
to base-class pointer commissionEmployeePtr
, which line 53 uses to invoke member function print
. This “crossover” is allowed because an object of a derived class is an object of its base class. Despite the fact that the base class CommissionEmployee
pointer points to a derived class BasePlusCommissionEmployee
object, the base class CommissionEmployee
’s print
member function is invoked (rather than BasePlusCommissionEmployee
’s print
function). The output of each print
member-function invocation in this program reveals that the invoked functionality depends on the type of the pointer (or reference) used to invoke the function, not the type of the object for which the member function is called. In Section 12.3.4, when we introduce virtual
functions, we demonstrate that it’s possible to invoke the object type’s functionality, rather than invoke the handle type’s functionality. We’ll see that this is crucial to implementing polymorphic behavior—the key topic of this chapter.
3.144.143.31