We now discuss the second part of our introduction to inheritance by creating and testing (a completely new and independent) class BasePlusCommissionEmployee
(Figs. 11.7–11.8), which contains a first name, last name, social security number, gross sales amount, commission rate and base salary.
1 // Fig. 11.7: BasePlusCommissionEmployee.h
2 // BasePlusCommissionEmployee class definition represents an employee
3 // that receives a base salary in addition to commission.
4 #ifndef BASEPLUS_H
5 #define BASEPLUS_H
6
7 #include <string> // C++ standard string class
8
9 class BasePlusCommissionEmployee
10 {
11 public:
12 BasePlusCommissionEmployee( const std::string &, const std::string &,
13 const std::string &, double = 0.0, double = 0.0, double = 0.0
);
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 void setGrossSales( double ); // set gross sales amount
25 double getGrossSales() const; // return gross sales amount
26
27 void setCommissionRate( double ); // set commission rate
28 double getCommissionRate() const; // return commission rate
29
30 void setBaseSalary( double ); // set base salary
31 double getBaseSalary() const; // return base salary
32
33 double earnings() const; // calculate earnings
34 void print() const; // print BasePlusCommissionEmployee object
35 private:
36 std::string firstName;
37 std::string lastName;
38 std::string socialSecurityNumber;
39 double grossSales; // gross weekly sales
40 double commissionRate; // commission percentage
41 double baseSalary; // base salary
42 }; // end class BasePlusCommissionEmployee
43
44 #endif
1 // Fig. 11.8: BasePlusCommissionEmployee.cpp
2 // Class BasePlusCommissionEmployee member-function definitions.
3 #include <iostream>
4 #include <stdexcept>
5 #include "BasePlusCommissionEmployee.h"
6 using namespace std;
7
8 // constructor
9 BasePlusCommissionEmployee::BasePlusCommissionEmployee(
10 const string &first, const string &last, const string &ssn,
11 double sales, double rate, double salary )
12 {
13 firstName = first; // should validate
14 lastName = last; // should validate
15 socialSecurityNumber = ssn; // should validate
16 setGrossSales( sales ); // validate and store gross sales
17 setCommissionRate( rate ); // validate and store commission rate
18 setBaseSalary( salary ); // validate and store base salary
19 } // end BasePlusCommissionEmployee constructor
20
21 // set first name
22 void BasePlusCommissionEmployee::setFirstName( const string &first )
23 {
24 firstName = first; // should validate
25 } // end function setFirstName
26
27 // return first name
28 string BasePlusCommissionEmployee::getFirstName() const
29 {
30 return firstName;
31 } // end function getFirstName
32
33 // set last name
34 void BasePlusCommissionEmployee::setLastName( const string &last )
35 {
36 lastName = last; // should validate
37 } // end function setLastName
38
39 // return last name
40 string BasePlusCommissionEmployee::getLastName() const
41 {
42 return lastName;
43 } // end function getLastName
44
45 // set social security number
46 void BasePlusCommissionEmployee::setSocialSecurityNumber(
47 const string &ssn )
48 {
49 socialSecurityNumber = ssn; // should validate
50 } // end function setSocialSecurityNumber
51
52 // return social security number
53 string BasePlusCommissionEmployee::getSocialSecurityNumber() const
54 {
55 return socialSecurityNumber;
56 } // end function getSocialSecurityNumber
57
58 // set gross sales amount
59 void BasePlusCommissionEmployee::setGrossSales( double sales )
60 {
61 if ( sales >= 0.0 )
62 grossSales = sales;
63 else
64 throw invalid_argument( "Gross sales must be >= 0.0" );
65 } // end function setGrossSales
66
67 // return gross sales amount
68 double BasePlusCommissionEmployee::getGrossSales() const
69 {
70 return grossSales;
71 } // end function getGrossSales
72
73 // set commission rate
74 void BasePlusCommissionEmployee::setCommissionRate( double rate )
75 {
76 if ( rate > 0.0 && rate < 1.0 )
77 commissionRate = rate;
78 else
79 throw invalid_argument( "Commission rate must be > 0.0 and < 1.0" );
80 } // end function setCommissionRate
81
82 // return commission rate
83 double BasePlusCommissionEmployee::getCommissionRate() const
84 {
85 return commissionRate;
86 } // end function getCommissionRate
87
88 // set base salary
89 void BasePlusCommissionEmployee::setBaseSalary( double salary )
90 {
91 if ( salary >= 0.0 )
92 baseSalary = salary;
93 else
94 throw invalid_argument( "Salary must be >= 0.0" );
95 } // end function setBaseSalary
96
97 // return base salary
98 double BasePlusCommissionEmployee::getBaseSalary() const
99 {
100 return baseSalary;
101 } // end function getBaseSalary
102
103 // calculate earnings
104 double BasePlusCommissionEmployee::earnings() const
105 {
106 return baseSalary + ( commissionRate * grossSales );
107 } // end function earnings
108
109 // print BasePlusCommissionEmployee object
110 void BasePlusCommissionEmployee::print() const
111 {
112 cout << "base-salaried commission employee: " << firstName << ' '
113 << lastName << "
social security number: " << socialSecurityNumber
114 << "
gross sales: " << grossSales
115 << "
commission rate: " << commissionRate
116 << "
base salary: " << baseSalary;
117 } // end function print
The BasePlusCommissionEmployee
header (Fig. 11.7) specifies class BasePlusCommissionEmployee
’s public
services, which include the BasePlusCommissionEmployee
constructor (lines 12–13) and member functions earnings
(line 33) and print
(line 34). Lines 15–31 declare public
get and set functions for the class’s private
data members (declared in lines 36–41) firstName
, lastName
, socialSecurityNumber
, grossSales
, commissionRate
and baseSalary
. These variables and member functions encapsulate all the necessary features of a base-salaried commission employee. Note the similarity between this class and class CommissionEmployee
(Figs. 11.4–11.5)—in this example, we do not yet exploit that similarity.
Class BasePlusCommissionEmployee
’s earnings
member function (defined in lines 104–107 of Fig. 11.8) computes the earnings of a base-salaried commission employee. Line 106 returns the result of adding the employee’s base salary to the product of the commission rate and the employee’s gross sales.
Figure 11.9 tests class BasePlusCommissionEmployee
. Lines 11–12 instantiate object employee
of class BasePlusCommissionEmployee
, passing "Bob"
, "Lewis"
, "333-33-3333"
, 5000
, .04
and 300
to the constructor as the first name, last name, social security number, gross sales, commission rate and base salary, respectively. Lines 19–25 use BasePlusCommissionEmployee
’s get functions to retrieve the values of the object’s data members for output. Line 27 invokes the object’s setBaseSalary
member function to change the base salary. Member function setBaseSalary
(Fig. 11.8, lines 89–95) ensures that data member baseSalary
is not assigned a negative value, because an employee’s base salary cannot be negative. Line 31 of Fig. 11.9 invokes the object’s print
member function to output the updated BasePlusCommissionEmployee
’s information, and line 34 calls member function earnings
to display the BasePlusCommissionEmployee
’s earnings.
1 // Fig. 11.9: fig11_09.cpp
2 // BasePlusCommissionEmployee class test program.
3 #include <iostream>
4 #include <iomanip>
5 #include "BasePlusCommissionEmployee.h"
6 using namespace std;
7
8 int main()
9 {
10 // instantiate BasePlusCommissionEmployee object
11 BasePlusCommissionEmployee
12 employee( "Bob", "Lewis", "333-33-3333", 5000, .04, 300
);
13
14 // set floating-point output formatting
15 cout << fixed << setprecision( 2 );
16
17 // get commission employee data
18 cout << "Employee information obtained by get functions:
"
19 << "
First name is " << employee.getFirstName()
20 << "
Last name is " << employee.getLastName()
21 << "
Social security number is "
22 << employee.getSocialSecurityNumber()
23 << "
Gross sales is " << employee.getGrossSales()
24 << "
Commission rate is " << employee.getCommissionRate()
25 << "
Base salary is " << employee.getBaseSalary() << endl;
26
27 employee.setBaseSalary( 1000 ); // set base salary
28
29 cout << "
Updated employee information output by print function:
"
30 << endl;
31 employee.print(); // display the new employee information
32
33 // display the employee's earnings
34 cout << "
Employee's earnings: $" << employee.earnings() << endl;
35 } // end main
Employee information obtained by get functions:
First name is Bob
Last name is Lewis
Social security number is 333-33-3333
Gross sales is 5000.00
Commission rate is 0.04
Base salary is 300.00
Updated employee information output by print function:
base-salaried commission employee: Bob Lewis
social security number: 333-33-3333
gross sales: 5000.00
commission rate: 0.04
base salary: 1000.00
Employee's earnings: $1200.00
Most of the code for class BasePlusCommissionEmployee
(Figs. 11.7–11.8) is similar, if not identical, to the code for class CommissionEmployee
(Figs. 11.4–11.5). For example, in class BasePlusCommissionEmployee
, private
data members firstName
and lastName
and member functions setFirstName
, getFirstName
, setLastName
and getLastName
are identical to those of class CommissionEmployee
. Classes CommissionEmployee
and BasePlusCommissionEmployee
also both contain private
data members socialSecurityNumber
, commissionRate
and grossSales
, as well as get and set functions to manipulate these members. In addition, the BasePlusCommissionEmployee
constructor is almost identical to that of class CommissionEmployee
, except that BasePlusCommissionEmployee
’s constructor also sets the baseSalary
. The other additions to class BasePlusCommissionEmployee
are private
data member baseSalary
and member functions setBaseSalary
and getBaseSalary
. Class BasePlusCommissionEmployee
’s print
member function is nearly identical to that of class CommissionEmployee
, except that BasePlusCommissionEmployee
’s print
also outputs the value of data member baseSalary
.
We literally copied code from class CommissionEmployee
and pasted it into class BasePlusCommissionEmployee
, then modified class BasePlusCommissionEmployee
to include a base salary and member functions that manipulate the base salary. This copy-and-paste approach is error prone and time consuming.
Software Engineering Observation 11.1
Copying and pasting code from one class to another can spread many physical copies of the same code and can spread errors throughout a system, creating a code-maintenance nightmare. To avoid duplicating code (and possibly errors), use inheritance, rather than the “copy-and-paste” approach, in situations where you want one class to “absorb” the data members and member functions of another class.
Software Engineering Observation 11.2
With inheritance, the common data members and member functions of all the classes in the hierarchy are declared in a base class. When changes are required for these common features, you need to make the changes only in the base class—derived classes then inherit the changes. Without inheritance, changes would need to be made to all the source code files that contain a copy of the code in question.