To test our Employee
hierarchy, the program in Fig. 12.17 creates an object of each of the three concrete classes SalariedEmployee
, CommissionEmployee
and BasePlusCommissionEmployee
. The program manipulates these objects, first with static binding, then polymorphically, using a vector
of Employee
pointers. Lines 22–27 create objects of each of the three concrete Employee
derived classes. Lines 32–38 output each Employee
’s information and earnings. Each member-function invocation in lines 32–37 is an example of static binding—at compile time, because we are using name handles (not pointers or references that could be set at execution time), the compiler can identify each object’s type to determine which print
and earnings
functions are called.
1 // Fig. 12.17: fig12_17.cpp
2 // Processing Employee derived-class objects individually
3 // and polymorphically using dynamic binding.
4 #include <iostream>
5 #include <iomanip>
6 #include <vector>
7 #include "Employee.h"
8 #include "SalariedEmployee.h"
9 #include "CommissionEmployee.h"
10 #include "BasePlusCommissionEmployee.h"
11 using namespace std;
12
13 void virtualViaPointer( const Employee * const ); // prototype
14 void virtualViaReference( const Employee & ); // prototype
15
16 int main()
17 {
18 // set floating-point output formatting
19 cout << fixed << setprecision( 2 );
20
21 // create derived-class objects
22 SalariedEmployee salariedEmployee(
23 "John", "Smith", "111-11-1111", 800 );
24 CommissionEmployee commissionEmployee(
25 "Sue", "Jones", "333-33-3333", 10000, .06 );
26 BasePlusCommissionEmployee basePlusCommissionEmployee(
27 "Bob", "Lewis", "444-44-4444", 5000, .04, 300 );
28
29 cout << "Employees processed individually using static binding:
";
30
31 // output each Employee's information and earnings using static binding
32 salariedEmployee.print();
33 cout << "
earned $" << salariedEmployee.earnings() << "
";
34 commissionEmployee.print();
35 cout << "
earned $" << commissionEmployee.earnings() << "
";
36 basePlusCommissionEmployee.print();
37 cout << "
earned $" << basePlusCommissionEmployee.earnings()
38 << "
";
39
40 // create vector of three base-class pointers
41 vector< Employee * > employees( 3 );
42
43 // initialize vector with pointers to Employees
44 employees[ 0 ] = &salariedEmployee;
45 employees[ 1 ] = &commissionEmployee;
46 employees[ 2 ] = &basePlusCommissionEmployee;
47
48 cout << "Employees processed polymorphically via dynamic binding:
";
49
50 // call virtualViaPointer to print each Employee's information
51 // and earnings using dynamic binding
52 cout << "Virtual function calls made off base-class pointers:
";
53
54 for ( const Employee *employeePtr : employees )
55 virtualViaPointer( employeePtr );
56
57 // call virtualViaReference to print each Employee's information
58 // and earnings using dynamic binding
59 cout << "Virtual function calls made off base-class references:
";
60
61 for ( const Employee *employeePtr : employees )
62 virtualViaReference( *employeePtr ); // note dereferencing
63 } // end main
64
65 // call Employee virtual functions print and earnings off a
66 // base-class pointer using dynamic binding
67 void virtualViaPointer( const Employee * const baseClassPtr )
68 {
69 baseClassPtr->print();
70 cout << "
earned $" << baseClassPtr->earnings() << "
";
71 } // end function virtualViaPointer
72
73 // call Employee virtual functions print and earnings off a
74 // base-class reference using dynamic binding
75 void virtualViaReference( const Employee &baseClassRef )
76 {
77 baseClassRef.print(); '
78 cout << "
earned $" << baseClassRef.earnings() << "
";
79 } // end function virtualViaReference
Employees processed individually using static binding:
salaried employee: John Smith
social security number: 111-11-1111
weekly salary: 800.00
earned $800.00
commission employee: Sue Jones
social security number: 333-33-3333
gross sales: 10000.00; commission rate: 0.06
earned $600.00
base-salaried commission employee: Bob Lewis
social security number: 444-44-4444
gross sales: 5000.00; commission rate: 0.04; base salary: 300.00
earned $500.00
Employees processed polymorphically using dynamic binding:
Virtual function calls made off base-class pointers:
salaried employee: John Smith
social security number: 111-11-1111
weekly salary: 800.00
earned $800.00
commission employee: Sue Jones
social security number: 333-33-3333
gross sales: 10000.00; commission rate: 0.06
earned $600.00
base-salaried commission employee: Bob Lewis
social security number: 444-44-4444
gross sales: 5000.00; commission rate: 0.04; base salary: 300.00
earned $500.00
Virtual function calls made off base-class references:
salaried employee: John Smith
social security number: 111-11-1111
weekly salary: 800.00
earned $800.00
commission employee: Sue Jones
social security number: 333-33-3333
gross sales: 10000.00; commission rate: 0.06
earned $600.00
base-salaried commission employee: Bob Lewis
social security number: 444-44-4444
gross sales: 5000.00; commission rate: 0.04; base salary: 300.00
earned $500.00
Line 41 creates the vector employees
, which contains three Employee
pointers. Line 44 aims employees[0]
at object salariedEmployee
. Line 45 aims employees[1]
at object commissionEmployee
. Line 46 aims employee[2]
at object basePlusCommissionEmployee
. The compiler allows these assignments, because a SalariedEmployee
is an Employee
, a CommissionEmployee
is an Employee
and a BasePlusCommissionEmployee
is an Employee
. Therefore, we can assign the addresses of SalariedEmployee
, CommissionEmployee
and BasePlusCommissionEmployee
objects to base-class Employee
pointers, even though Employee
is an abstract class.
Lines 54–55 traverse vector employees
and invoke function virtualViaPointer
(lines 67–71) for each element in employees
. Function virtualViaPointer
receives in parameter baseClassPtr
the address stored in an employees
element. Each call to virtualViaPointer
uses baseClassPtr
to invoke virtual
functions print
(line 69) and earnings
(line 70). Function virtualViaPointer
does not contain any SalariedEmployee
, CommissionEmployee
or BasePlusCommissionEmployee
type information. The function knows only about base-class type Employee
. Therefore, the compiler cannot know which concrete class’s functions to call through baseClassPtr
. Yet at execution time, each virtual-function invocation correctly calls the function on the object to which baseClassPtr
currently points. The output illustrates that the appropriate functions for each class are indeed invoked and that each object’s proper information is displayed. For instance, the weekly salary is displayed for the SalariedEmployee
, and the gross sales are displayed for the CommissionEmployee
and BasePlusCommissionEmployee
. Also, obtaining the earnings of each Employee
polymorphically in line 70 produces the same results as obtaining these employees’ earnings via static binding in lines 33, 35 and 37. All virtual
function calls to print
and earnings
are resolved at runtime with dynamic binding.
Finally, lines 61–62 traverse employees
and invoke function virtualViaReference
(lines 75–79) for each vector
element. Function virtualViaReference
receives in its parameter baseClassRef
(of type const Employee &
) a reference to the object obtained by dereferencing the pointer stored in each employees
element (line 62). Each call to virtualViaReference
invokes virtual
functions print
(line 77) and earnings
(line 78) via baseClassRef
to demonstrate that polymorphic processing occurs with base-class references as well. Each virtual
-function invocation calls the function on the object to which baseClassRef
refers at runtime. This is another example of dynamic binding. The output produced using base-class references is identical to the output produced using base-class pointers.