12.8. Case Study: Payroll System Using Polymorphism and Runtime Type Information with Downcasting, dynamic_cast, typeid and type_info

Recall from the problem statement at the beginning of Section 12.6 that, for the current pay period, our fictitious company has decided to reward BasePlusCommissionEmployees by adding 10 percent to their base salaries. When processing Employee objects polymorphically in Section 12.6.5, we did not need to worry about the “specifics.” Now, however, to adjust the base salaries of BasePlusCommissionEmployees, we have to determine the specific type of each Employee object at execution time, then act appropriately. This section demonstrates the powerful capabilities of runtime type information (RTTI) and dynamic casting, which enable a program to determine an object’s type at execution time and act on that object accordingly.1

1. Some compilers require that RTTI be enabled before it can be used in a program. The compilers we used for testing this book’s examples—GNU C++ 4.7, Visual C++ 2012 and Xcode 4.5 LLVM—each enable RTTI by default.

Figure 12.19 uses the Employee hierarchy developed in Section 12.6 and increases by 10 percent the base salary of each BasePlusCommissionEmployee. Line 21 declares three-element vector employees that stores pointers to Employee objects. Lines 24–29 populate the vector with the addresses of dynamically allocated objects of classes SalariedEmployee (Figs. 12.1112.12), CommissionEmployee (Figs. 12.1312.14) and BasePlusCommissionEmployee (Figs. 12.1512.16). Lines 32–52 iterate through the employees vector and display each Employee’s information by invoking member function print (line 34). Recall that because print is declared virtual in base class Employee, the system invokes the appropriate derived-class object’s print function.


 1   // Fig. 12.19: fig12_19.cpp
 2   // Demonstrating downcasting and runtime type information.
 3   // NOTE: You may need to enable RTTI on your compiler
 4   // before you can compile this application.
 5   #include <iostream>
 6   #include <iomanip>
 7   #include <vector>
 8   #include <typeinfo>
 9   #include "Employee.h"
10   #include "SalariedEmployee.h"
11   #include "CommissionEmployee.h"
12   #include "BasePlusCommissionEmployee.h"
13   using namespace std;
14
15   int main()
16   {
17      // set floating-point output formatting
18      cout << fixed << setprecision( 2 );
19
20      // create vector of three base-class pointers
21      vector < Employee * > employees( 3 );
22
23      // initialize vector with various kinds of Employees
24      employees[ 0 ] = new SalariedEmployee(              
25         "John", "Smith", "111-11-1111", 800 );           
26      employees[ 1 ] = new CommissionEmployee(            
27         "Sue", "Jones", "333-33-3333", 10000, .06 );     
28      employees[ 2 ] = new BasePlusCommissionEmployee(    
29         "Bob", "Lewis", "444-44-4444", 5000, .04, 300 ); 
30
31      // polymorphically process each element in vector employees
32      for ( Employee *employeePtr : employees )
33      {
34         employeePtr->print(); // output employee information
35         cout << endl;
36
37         // attempt to downcast pointer                                  
38         BasePlusCommissionEmployee *derivedPtr =                        
39            dynamic_cast < BasePlusCommissionEmployee * >( employeePtr );
40
41         // determine whether element points to a BasePlusCommissionEmployee
42         if ( derivedPtr != nullptr ) // true for "is a" relationship
43         {
44            double oldBaseSalary = derivedPtr->getBaseSalary();
45            cout << "old base salary: $" << oldBaseSalary << endl;
46            derivedPtr->setBaseSalary( 1.10 * oldBaseSalary );
47            cout << "new base salary with 10% increase is: $"
48               << derivedPtr->getBaseSalary() << endl;
49         } // end if
50
51         cout << "earned $" << employeePtr->earnings() << " ";
52      } // end for
53
54      // release objects pointed to by vector's elements
55      for ( const Employee *employeePtr : employees )
56      {
57         // output class name                        
58         cout << "deleting object of "               
59            << typeid( *employeePtr ).name() << endl;
60
61         delete employeePtr;
62      } // end for
63   } // end main


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
old base salary: $300.00
new base salary with 10% increase is: $330.00
earned $530.00

deleting object of class SalariedEmployee
deleting object of class CommissionEmployee
deleting object of class BasePlusCommissionEmployee


Fig. 12.19. Demonstrating downcasting and runtime type information.

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

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