Class Employee
(Figs. 12.9–12.10, discussed in further detail shortly) provides functions earnings
and print
, in addition to various get and set functions that manipulate Employee
’s data members. An earnings
function certainly applies generally to all employees, but each earnings calculation depends on the employee’s class. So we declare earnings
as pure virtual
in base class Employee
because a default implementation does not make sense for that function—there is not enough information to determine what amount earnings
should return. Each derived class overrides earnings
with an appropriate implementation. To calculate an employee’s earnings, the program assigns the address of an employee’s object to a base class Employee
pointer, then invokes the earnings
function on that object. We maintain a vector
of Employee
pointers, each of which points to an Employee
object. Of course, there cannot be Employee objects, because Employee is an abstract class—because of inheritance, however, all objects of all concrete derived classes of Employee may nevertheless be thought of as Employee objects. The program iterates through the vector
and calls function earnings
for each Employee
object. C++ processes these function calls polymorphically. Including earnings
as a pure virtual
function in Employee
forces every direct derived class of Employee
that wishes to be a concrete class to override earnings
.
Function print
in class Employee
displays the first name, last name and social security number of the employee. As we’ll see, each derived class of Employee
overrides function print
to output the employee’s type (e.g., "salaried employee:"
) followed by the rest of the employee’s information. Function print
in the derived classes could also call earnings
, even though earnings
is a pure-virtual
function in base class Employee
.
The diagram in Fig. 12.8 shows each of the four classes in the hierarchy down the left side and functions earnings
and print
across the top. For each class, the diagram shows the desired results of each function. Italic text represents where the values from a particular object are used in the earnings
and print
functions. Class Employee
specifies “= 0
” for function earnings
to indicate that this is a pure virtual
function and hence has no implementation. Each derived class overrides this function to provide an appropriate implementation. We do not list base class Employee
’s get and set functions because they’re not overridden in any of the derived classes—each of these functions is inherited and used “as is” by each of the derived classes.
Let’s consider class Employee
’s header (Fig. 12.9). The public
member functions include a constructor that takes the first name, last name and social security number as arguments (lines 11–12); a virtual destructor (line 13); set functions that set the first name, last name and social security number (lines 15, 18 and 21, respectively); get functions that return the first name, last name and social security number (lines 16, 19 and 22, respectively); pure virtual
function earnings
(line 25) and virtual
function print
(line 26).
1 // Fig. 12.9: Employee.h
2 // Employee abstract base class.
3 #ifndef EMPLOYEE_H
4 #define EMPLOYEE_H
5
6 #include <string> // C++ standard string class
7
8 class Employee
9 {
10 public:
11 Employee( const std::string &, const std::string &,
12 const std::string & );
13 virtual ~Employee() { } // virtual destructor
14
15 void setFirstName( const std::string & ); // set first name
16 std::string getFirstName() const; // return first name
17
18 void setLastName( const std::string & ); // set last name
19 std::string getLastName() const; // return last name
20
21 void setSocialSecurityNumber( const std::string & ); // set SSN
22 std::string getSocialSecurityNumber() const; // return SSN
23
24 // pure virtual function makes Employee an abstract base class
25 virtual double earnings() const = 0; // pure virtual
26 virtual void print() const; // virtual
27 private:
28 std::string firstName;
29 std::string lastName;
30 std::string socialSecurityNumber;
31 }; // end class Employee
32
33 #endif // EMPLOYEE_H
Recall that we declared earnings
as a pure virtual
function because first we must know the specific Employee
type to determine the appropriate earnings
calculations. Declaring this function as pure virtual
indicates that each concrete derived class must provide an earnings
implementation and that a program can use base-class Employee
pointers to invoke function earnings
polymorphically for any type of Employee
.
Figure 12.10 contains the member-function definitions for class Employee
. No implementation is provided for virtual
function earnings
. The Employee
constructor (lines 9–14) does not validate the social security number. Normally, such validation should be provided.
1 // Fig. 12.10: Employee.cpp
2 // Abstract-base-class Employee member-function definitions.
3 // Note: No definitions are given for pure virtual functions.
4 #include <iostream>
5 #include "Employee.h" // Employee class definition
6 using namespace std;
7
8 // constructor
9 Employee::Employee( const string &first, const string &last,
10 const string &ssn )
11 : firstName( first ), lastName( last ), socialSecurityNumber( ssn )
12 {
13 // empty body
14 } // end Employee constructor
15
16 // set first name
17 void Employee::setFirstName( const string &first )
18 {
19 firstName = first;
20 } // end function setFirstName
21
22 // return first name
23 string Employee::getFirstName() const
24 {
25 return firstName;
26 } // end function getFirstName
27
28 // set last name
29 void Employee::setLastName( const string &last )
30 {
31 lastName = last;
32 } // end function setLastName
33
34 // return last name
35 string Employee::getLastName() const
36 {
37 return lastName;
38 } // end function getLastName
39
40 // set social security number
41 void Employee::setSocialSecurityNumber( const string &ssn )
42 {
43 socialSecurityNumber = ssn; // should validate
44 } // end function setSocialSecurityNumber
45
46 // return social security number
47 string Employee::getSocialSecurityNumber() const
48 {
49 return socialSecurityNumber;
50 } // end function getSocialSecurityNumber
51
52 // print Employee's information (virtual, but not pure virtual)
53 void Employee::print() const
54 {
55 cout << getFirstName() << ' ' << getLastName()
56 << "
social security number: " << getSocialSecurityNumber();
57 } // end function print
The virtual
function print
(lines 53–57) provides an implementation that will be overridden in each of the derived classes. Each of these functions will, however, use the abstract class’s version of print
to print information common to all classes in the Employee
hierarchy.