12.6.5. Demonstrating Polymorphic Processing

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


Fig. 12.17. Employee class hierarchy driver program.

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.58.3.72