Question: 12.8 Programming Project #7: An Employee Class Hierarchy Background The code that you wrote for the second Employee project only works for hourly employees. Now
12.8 Programming Project #7: An Employee Class Hierarchy
Background
The code that you wrote for the second Employee project only works for hourly employees. Now that we have studied polymorphism, we can begin to make our payroll program more general. The most important thing we will do is enable polymorphism in our Employee class hierarchy, so that employee objects of different types automatically behave correctly.
Objectives
Continue gaining experience with object-oriented design
Learn to create a class hierarchy that is enabled for polymorphism
Learn to use polymorphism in a program.
The Program
We will rename Employee to HourlyEmployee, and then create two new classes, Employee and SalariedEmployee, as depicted in the class diagram below.
(Items preceded by dashes are private, those preceded by a # are protected, and public members start with a +. Static members appear underlined.)
Employee is an abstract class, meaning that it exists to hold what is common to all its derived classes, and is not to be instantiated directly by users. For this reason, it has no public constructors.
In addition to defining all things common to the derived employee classes, Employee defines a virtual destructor and declares four pure virtual functions, which are overridden in the derived classes (see the italicized functions in Employee above). All of these functions have bodies in Employee except calcPay, and are called explicitly from their derived counterparts. Note that readData functions as well as default constructors have protected access. This is because we don't want users to create instances of the concrete, derived employee objects directly without complete information.
Also, remember that base classes must always have a virtual destructor, even if the body of that destructor is empty (which is what = default accomplishes here). Finally, the parameterized constructors for the derived classes take all pertinent parameters for objects of their type (which includes data common to all employees).
The key functions work as follows:
read
This static member function creates an empty, derived employee object and then calls readData to initialize it. It returns a pointer to a new object, if data was read correctly, or nullptr if there was an input error. For example, HourlyEmployee::read creates a new, empty HourlyEmployee object on the heap, emp, say. and then calls emp->readData. HourlyEmployee::readData calls Employee::readData to read in the common employee fields from a file, and then reads in the hourly wage and hours worked. The pointer to the initialized object (or nullptr) is then returned.
readData
As explained above, this function first calls the base class implementation of readData, and then reads data frorm the file for its type of object (HourlyEmployee or SalariedEmployee).
write
This function works similarly to readData: it first calls Employee::write to write out the common data to the file, then writes out the specific derived class data.
printCheck
This function first calls Employee::printCheck to print the common check header, then prints the rest of the check according to the type of the object. See the sample output below to see how SalariedEmployee checks should look.
calcPay
Hourly Employees: An hourly employee's gross pay is calculated by multiplying the hours worked by their hourly wage. Be sure to give time-and-a-half for overtime (anything over 40 hours). To compute the net pay, deduct 20% of the gross for Federal income tax, and 7.5% of the gross for state income tax.
Salaried Employees: A salaried employee's gross pay is just their weekly salary value. To compute the net pay for a salaried employee, deduct 20% of the gross for Federal income tax, 7.5% of the gross for state income tax, and 5.24% for benefits.
The main() Function
Your driver will provide the same set of options as in the previous project. However, your driver code should be somewhat simpler because you will now create a vector of Employee pointers, and store the pointers to your objects in this vector. Add heap pointers to the following employees to your vector:
HourlyEmployee(1, "H. Potter", "Privet Drive", "201-9090", 40, 12.00); SalariedEmployee(2, "A. Dumbledore", "Hogwarts", "803-1230", 1200); HourlyEmployee(3, "R. Weasley", "The Burrow", "892-2000", 40, 10.00); SalariedEmployee(4, "R. Hagrid", "Hogwarts", "910-8765", 1000);
You can then use a simple for-loop to save each object's data to the file.
Here is a sample execution of Option 1:
This program has two options: 1 - Create a data file, or 2 - Read data from a file and print paychecks. Please enter (1) to create a file or (2) to print checks:1 Please enter a file name: employee.txt Data file created ... you can now run option 2.
The contents of the file employee.txt should be:
1 H. Potter Privet Drive 201-9090 40 12 2 A. Dumbledore Hogwarts 803-1230 1200 3 R. Weasley The Burrow 892-2000 40 10 4 R. Hagrid Hogwarts 910-8765 1000
When you run option 2, your program should create a new vector of Employee pointers. Make four calls to either HourlyEmployee::read or SalariedEmployee::read, according to the same order that you wrote the objects in part 1. Add the pointers returned by read to your vector. Then loop through the vector printing out the checks. Here is an execution of Option 2:
//What its suppose to look like
This program has two options: 1 - Create a data file, or 2 - Read data from a file and print paychecks. Please enter (1) to create a file or (2) to print checks:2 Please enter a file name: employee.dat ....................UVU Computer Science Dept................................. Pay to the order of H. Potter....................................$348.00 United Community Credit Union .............................................................................. Hours worked: 40.00 HourlyWage: 12.00 ....................UVU Computer Science Dept................................. Pay to the order of A. Dumbledore....................................$807.12 United Community Credit Union .............................................................................. Salary: 1200.00 ....................UVU Computer Science Dept................................. Pay to the order of R. Weasley....................................$290.00 United Community Credit Union .............................................................................. Hours worked: 40.00 HourlyWage: 10.00 ....................UVU Computer Science Dept................................. Pay to the order of R. Hagrid....................................$672.60 United Community Credit Union .............................................................................. Salary: 1000.00
//something similar but only using condensed into 3 folders (employee.h, employee.cpp, and main)
Driver.cpp --------------------------- #include#include #include #include #include #include #include "MyVector.h" #include "Hourly.h" #include "Salaried.h" #include "Employee.h" #include "Exception.h" using namespace std; const int ONE = 1, TWO = 2, SIZE = 4, HOURLY = 6, SALARIED = 5; int main() { int objectCount = 0; int userOption = 0; string userFileName = "0"; // Presents the user with a menu of choices : // create a data file, or read data from a file and print checks. cout > userOption; if (userOption != ONE && userOption != TWO) { cout ::max(), ' '); } } while (userOption != ONE && userOption != TWO); MyVector payroll; //Employee* payroll[SIZE]; // Creat array of object pointers for following four objects //If the user selects the first option if (userOption == ONE) { payroll.push_back(new Hourly(1, "H. Potter", "Privet Drive", "201-9090", 40, 12.00)); payroll.push_back(new Salaried(2, "A. Dumbledore", "Hogewarts", "803-1230", 1200)); payroll.push_back(new Hourly(3, "R. Weasley", "The Burrow", "892-2000", 40, 10.00)); payroll.push_back(new Salaried(4, "R. Hagrid", "Hogwarts", "910-8765", 1000)); cout > userFileName; // Create an ofstream object and open a file. ofstream writeToFile(userFileName.c_str()); // Pass just the file name as the parameter(no path) so that your program assumes // the file to be in the same folder as your executable file. // Use a for loop to save each object's data to the file. MyVector temp; for (int i = 0; i writeData(writeToFile); } catch (WriteErrorException badWrite) { cout > userFileName; ifstream readFile; // Open the file that the user iputs. do { readFile.open(userFileName.c_str()); if (readFile.fail()) { readFile.clear(); cout > userFileName; if (userFileName == "e" || userFileName == "E") { exit(1); } } } while (readFile.fail()); // Array of pointers for objects to be read in string dataType; Employee* ePtr = NULL; while (readFile >> dataType) // read in first line, quit when end of file is encountered { // see what kind of data we have if (dataType == "hourly") ePtr = new Hourly; else if (dataType == "salaried") ePtr = new Salaried; else cout readData(readFile); } catch (EofException badRead) { cout printCheck() #include #include #include using namespace std; Employee::Employee() { empNum = 0; name = ""; address = ""; phoneNum = ""; } Employee::Employee(int tempNum, string tempName, string tempAddress, string tempPhNum) { empNum = tempNum; name = tempName; address = tempAddress; phoneNum = tempPhNum; } void Employee::setEmpNumber(int tempNum) { empNum = tempNum; } void Employee::setName(string tempName) { name = tempName; } void Employee::setAddress(string tempAddress) { address = tempAddress; } void Employee::setPhoneNum(string tempPhNum) { phoneNum = tempPhNum; } int Employee::getEmpNumber() const { return empNum; } string Employee::getName() const { return name; } string Employee::getAddress() const { return address; } string Employee::getPhoneNum() const { return phoneNum; } // calcPay() will have no implementation in Employee class void Employee::readData(ifstream& in) { string tempString; in >> empNum; if (in.eof()) { throw EofException(); } else if (in.fail()) { throw invalid_argument(tempString); } else if (in.bad()) { throw out_of_range(tempString); } in.ignore(); getline(in, name); if (in.eof()) { throw EofException(); } getline(in, address); if (in.eof()) { throw EofException(); } getline(in, phoneNum); if (in.eof()) { throw EofException(); } } void Employee::writeData(ofstream& out) { out getEmpNumber() getName() getAddress() getPhoneNum() getName(); return out.str(); } ------------------------------------------------ Employee.h --------------------------- #include #include #include #pragma once using namespace std; class Employee { protected: int empNum; string name, address, phoneNum; public: Employee(); Employee(int, string, string, string); void setEmpNumber(int); void setName(string); void setAddress(string); void setPhoneNum(string); int getEmpNumber() const; string getName() const; string getAddress() const; string getPhoneNum() const; virtual double calcPay() const = 0; virtual void readData(ifstream&); virtual void writeData(ofstream&); virtual string printCheck() const; }; ------------------------------------------------ hourly.cpp --------------------------- #include "Employee.h" #include "Hourly.h" #include "Exception.h" #include #include #include #include using namespace std; Hourly::Hourly() { hrlyWage = 0; hrsWorked = 0; } Hourly::Hourly(int _empNum, string _name, string _address, string _phoneNum, double _hrsWorked, double _hrlyWage) : Employee(_empNum, _name, _address, _phoneNum) { //empNum = _empNum; /ame = _name; //address = _address; //phoneNum = _phoneNum; hrsWorked = _hrsWorked; hrlyWage = _hrlyWage; } void Hourly::setHrlyWage(double tempWage) { hrlyWage = tempWage; } void Hourly::setHrsWorked(double tempHours) { hrsWorked = tempHours; } double Hourly::getHrlyWage() const { return hrlyWage; } double Hourly::getHrsWorked() const { return hrsWorked; } // To compute the net pay, deduct 20% of the gross for Federal income tax, and 7.5% of the gross for state income tax. double Hourly::calcPay() const { double netPay, grossPay, overTimeHrs, regHours = 40, federalTax = 0.20, stateTax = 0.075, timeAndHalf = 1.5; if (hrsWorked > regHours) { overTimeHrs = hrsWorked - regHours; grossPay = ((regHours * hrlyWage) + ((overTimeHrs * hrlyWage) * timeAndHalf)); } else { grossPay = hrsWorked * hrlyWage; } netPay = grossPay - ((grossPay * federalTax) + (grossPay * stateTax)); return netPay; } void Hourly::readData(ifstream& in) { string tempString; in >> hrlyWage; if (in.eof()) { throw EofException(); } else if (in.fail()) { throw invalid_argument(tempString); } else if (in.bad()) { throw out_of_range(tempString); } in >> hrsWorked; if (in.eof()) { throw EofException(); } else if (in.fail()) { throw invalid_argument(tempString); } else if (in.bad()) { throw out_of_range(tempString); } Employee::readData(in); } void Hourly::writeData(ofstream& out) { out calcPay() getHrsWorked() getHrlyWage(); return out.str(); } ------------------------------------------------ Hourly.h --------------------------- #include "Employee.h" #include #include #include #pragma once using namespace std; class Hourly : public Employee { private: double hrlyWage, hrsWorked; public: Hourly(); Hourly(int, string, string, string, double, double); // setHrlyWage Function void setHrlyWage(double); // setHrsWorked Function void setHrsWorked(double); // getHrlyWage Function double getHrlyWage() const; // getHrsWorked Function double getHrsWorked() const; // calcPay Function double calcPay() const; // readData Function void readData(ifstream&); // writeData Function void writeData(ofstream&); // printCheck function string printCheck() const; }; ------------------------------------------------ Salaried.cpp --------------------------- #include "Employee.h" #include "Salaried.h" #include "Exception.h" #include #include #include #include using namespace std; Salaried::Salaried() { salary = 0; } Salaried::Salaried(int _empNum, string _name, string _address, string _phoneNum, double _salary) : Employee(_empNum, _name, _address, _phoneNum) { //empNum = _empNum; /ame = _name; //address = _address; //phoneNum = _phoneNum; salary = _salary; } void Salaried::setSalary(double _salary) { salary = _salary; } double Salaried::getSalary() const { return salary; } // To compute the net pay for a salaried employee, deduct 20% of the gross for Federal income tax, // 7.5% of the gross for state income tax, and 5.24% of the gross for benefits. double Salaried::calcPay() const { double netPay, federalTax = 0.20, stateTax = 0.075, benefits = 0.0524; netPay = salary - ((salary * federalTax) + (salary * stateTax) + (salary * benefits)); return netPay; } void Salaried::readData(ifstream& in) { string tempString; in >> salary; if (in.eof()) { throw EofException(); } else if (in.fail()) { throw invalid_argument(tempString); } else if (in.bad()) { throw out_of_range(tempString); } Employee::readData(in); } void Salaried::writeData(ofstream& out) { out calcPay() getSalary(); return out.str(); } ------------------------------------------------ Salaried.h --------------------------- #include "Employee.h" #include #include #include #pragma once using namespace std; class Salaried : public Employee { private: double salary; public: Salaried(); Salaried(int, string, string, string, double); // setSalary Function void setSalary(double); // getSalary Function double getSalary() const; // calcPay Function double calcPay() const; // readData Function void readData(ifstream&); // writeData Function void writeData(ofstream&); // printCheck function string printCheck() const; }; ------------------------------------------------ Exception.cpp --------------------------- #include "Exception.h" #include #include #include using namespace std; WriteErrorException::WriteErrorException() { messageBadWrite = "Error writing the data to file! Program cannot continue!"; } string WriteErrorException::getBadWriteMessage() const { return messageBadWrite; } EofException::EofException() { messageEof = "End of File (eof) encountered before data was read! Program cannot continue!"; } string EofException::getEofMessage() const { return messageEof; } ------------------------------------------------ Exception.h --------------------------- #include using namespace std; #pragma once class WriteErrorException { private: string messageBadWrite; public: WriteErrorException(); string getBadWriteMessage() const; }; class EofException { private: string messageEof; public: EofException(); string getEofMessage() const; }; ------------------------------------------------ MyVector.h --------------------------- #include #include "Employee.h" using namespace std; #pragma once template class MyVector { private: const int TWO = 2; // Decided I should add this const int unsigned int vectorSize; unsigned int vectorCapacity; T *myVectorArray; // Somehow I would like to create this so any variable type could be used. Maybe void *myVectorArray // ***AWESOME*** Now it will :-) public: MyVector(); MyVector (int); MyVector(const MyVector &); ~MyVector(); // function size int size() const; // function capacity int capacity() const; //function clear void clear(); //function push_back void push_back(const T&); // function at T at(unsigned int)const; //operator= as a member function MyVector & operator=(const MyVector &); // operator&); }; //**************************************************************************************** template MyVector ::MyVector() //: myVectorArray(new T[TWO]) { vectorSize = 0; vectorCapacity = TWO; myVectorArray = new T[vectorCapacity]; } template MyVector ::MyVector(int n) { vectorSize = 0; vectorCapacity = n; myVectorArray = new T[vectorCapacity]; } template MyVector ::MyVector(const MyVector & toCopy) { vectorSize = toCopy.size(); // initialize size to parameter object's size vectorCapacity = toCopy.capacity(); // initialize capacity to parameter object's capacity myVectorArray = new T[vectorCapacity]; // initialize myVectorArray as a new int array (dynamically allocated) for (unsigned int i = 0; i MyVector & MyVector ::operator=(const MyVector & rho) // Declare function operator= as a member function of the vector class { if (this == &rho) // Test for self assignment with if statement { return *this; } delete[] this->myVectorArray; // Free up the storage of the left hand object using delete[] function this->vectorSize = rho.vectorSize; // Make size of this equal to size of right hand object using MyVector size() function this->vectorCapacity = rho.vectorCapacity; // Make capacity of this equal to capacity of right hand object using MyVector capacity() function this->myVectorArray = new T[vectorCapacity]; for (unsigned int i = 0; i myVectorArray[i] = rho.myVectorArray[i]; } return *this; // Return this object } // Destructor should clean up allocated storage from the heap here. template MyVector ::~MyVector() { if (myVectorArray != nullptr) // Won't let me use NULL, I guess it's not a keyword. { // So I went with nullptr instead of defining NULL. delete[] myVectorArray; myVectorArray = nullptr; } } template int MyVector ::size() const { return vectorSize; } template int MyVector ::capacity() const { return vectorCapacity; } template void MyVector ::clear() { delete[] myVectorArray; vectorCapacity = TWO; myVectorArray = new T[vectorCapacity]; vectorSize = 0; } template void MyVector ::push_back(const T& n) { T *tempArray; if (vectorSize + 1 > vectorCapacity) // if the array capacity won't hold another value { vectorCapacity *= TWO; // double the size of the array capacity tempArray = new T[vectorCapacity]; // Dynamically allocate a new array of integers // doubled capacity to be the capacity of the new array. for (unsigned int i = 0; i myVectorArray; // Delete the original array. myVectorArray = tempArray; } myVectorArray[vectorSize] = n; // Add the new element at the next open slot in the new array. vectorSize++; // Increment the size; } template T MyVector ::at(unsigned int idx)const { if (idx >= vectorSize) // if index is greater than size { throw idx; // throw the index back at them } else { return myVectorArray[idx]; } } template ostream& operator& rho) { out > Employee empNum: int name: String addreSs : string phone: string # Employee( )-default # readData( : ifstream) : void # ) Employee(num:int, name:string, addr:string, phone:string + virtual "Employee() - default + getEmpNum(): int + getName() : string + getAddress() : string + getPhone(): string + setName(string) : void + setAddress(string): void + setPhone(string) : void + write(: ofstream) : void + calcPaiy + printCheck(): void : double HourlyEmployee SalariedEmployee hoursWorked: double salary: double hourlyWage: double # HourlyEmployee( ) = default #readData( : ifstream) : void override + HourlyEmployee(...) + getHoursWorked(): double + getHourlyWage() : double + setHoursWorked(double): void + setHourlyWage(double): void write(: ofstream) : void override + calcPay) : double ov + printCheck(): void override + read(: ifstream) : HourlyEmployee* # SalariedEm ployee( ) default #readData( : ifstream) : void override + SalariedEmployee(...) + getSalary() : double + setSalary(double): void + write(: ofstream ) : void override + calcPay() : double override + printCheck( ) : void override + read(: ifstream) : SalariedEmployee'* erride
Step by Step Solution
There are 3 Steps involved in it
Get step-by-step solutions from verified subject matter experts
