Skip to content

Intermediate Project 8 — Payroll System

Difficulty: Intermediate · Estimated effort: 14–18 hours · Prerequisites: Module 6 — Inheritance, Module 7 — Polymorphism, Module 12 — Templates, Module 14 — The STL with OOP · Combines: several kinds of employee, one pay run, a creation point, money as a type

This is one of the designated integration projects. It must use, explicitly and in writing: multiple classes · relationships between classes · encapsulation · inheritance or composition · polymorphism · the STL · exception handling.

No complete solution is provided. The employee kinds are described by their pay rules, not by a class list.


1. Scenario

A small firm pays four kinds of people: salaried staff, hourly workers, commission-only sales staff, and hourly workers who also earn commission. The pay run happens monthly, prints a payslip per person, and must total to the same figure as the sum of the individual pays — a reconciliation the firm checks by hand today and gets wrong about once a year.


2. Problem statement

Build the payroll system: employee types with genuinely different pay rules, a monthly run producing payslips and totals, deduction rules applied consistently, an employee creation point that reads a file, and money arithmetic that cannot lose a penny.


3. User requirements

  • [ ] Register employees of the four kinds, with the data each kind needs.
  • [ ] Run a month's payroll and print a payslip for each employee.
  • [ ] See the gross total, the deduction total and the net total.
  • [ ] Change an employee's rate without changing their kind.
  • [ ] Load employees from a file, and be told the line number of a bad record.
  • [ ] Reconcile: the printed total equals the sum of the individual net pays, exactly.

4. Functional requirements

  • [ ] An abstract Employee with name(), grossPay(period), payKind() and a clone or a creation function.
  • [ ] Four concrete kinds, with at least one sharing behaviour with another through a base intermediate class or through composition — your choice, justified.
  • [ ] A Money value type in integer minor units, with +, -, * by a rate and <<.
  • [ ] Deduction rules applied by a separate component, not inside the employee types.
  • [ ] A Payroll owning employees, running the period and producing payslips.
  • [ ] A creation point reading a file: kind, name, rates, hours.
  • [ ] Errors for an unknown kind, a negative rate, and a malformed record.

5. Non-functional requirements

  • [ ] All money arithmetic in integers; conversion only at display.
  • [ ] No rounding discrepancy between a payslip and the total — the reconciliation test proves it.
  • [ ] Pay computation is free of side effects: running a period twice gives the same numbers.
  • [ ] Adding a fifth employee kind touches one new file plus the creation point.
  • [ ] Builds warning-free with g++ -std=c++17 -Wall -Wextra -Werror.

6. Suggested features

  • Overtime at an increased rate above a threshold, with a documented threshold.
  • Year-to-date totals per employee, held outside the employee object.
  • A PayRun value object that owns the payslips for one period, and a report comparing two runs.
  • A template Repository<T> for employees and for payslips, if it genuinely removes duplication.

7. OOP concepts involved

Concept Required Where it appears
Multiple classes yes Employee + four kinds, maybe an intermediate kind, Money, deduction rules, Payroll, Payslip
Relationships yes Payroll ◆ employees; payslip ──> employee; deductions injected into the run
Encapsulation yes Money is always valid; rates cannot be negative; hours cannot be negative
Inheritance or composition yes At least one kind reuses another's rule — and you must say whether by inheritance or by composition, and why
Polymorphism yes grossPay dispatches per kind; the run loop contains no kind checks
The STL yes std::vector of employees, std::map for kind counts, std::accumulate for totals
Exception handling yes Unknown kind, bad rate and malformed record throw distinct types

8. Suggested design considerations

The fourth kind is the design test. Hourly-plus-commission shares behaviour with two others. Inherit from one and reimplement the other? Inherit from both and meet the diamond? Or compose a PayRule from two parts? There is a good answer and a bad answer, and the reasoning is what is marked.

Deductions do not belong in the employee. An employee knows what they earn; the payroll knows what the state takes. Keeping them apart is what lets a tax-table change touch one file.

Money as a type pays for itself immediately. Once Money exists with a correct operator+ and a documented rounding rule for multiplication by a rate, the reconciliation test passes or fails for real reasons rather than for floating-point ones.

Reconcile in the test, not by eye. Sum the payslips and compare with the printed total as integers. That test is the one the firm actually needs.


9. Minimum viable version

Money, two employee kinds, a Payroll that runs a period and prints payslips and a total. Creation by hand in main.


10. Intermediate extension

Add the other two kinds, including the combined one, plus the deduction component and the reconciliation test. Then add a third deduction rule and count the files it touched.


11. Advanced extension

Add file-driven employee creation, a PayRun record of a period, and year-to-date totals held outside the employees. Then add a fifth kind and verify the change cost you predicted; if it took more files than predicted, say which assumption was wrong.


12. Testing checklist

  • [ ] A salaried employee's monthly gross is exactly the annual figure divided by twelve, per the documented rounding rule
  • [ ] An hourly employee's gross uses the hours given, including zero
  • [ ] Commission-only pay on zero sales is zero, not negative
  • [ ] The combined kind's pay equals the sum of its two parts, to the penny
  • [ ] The gross total equals the sum of the individual gross pays, exactly
  • [ ] Net pay equals gross minus deductions for every employee
  • [ ] Running the same period twice produces identical numbers
  • [ ] A negative rate is refused, and the employee is not created
  • [ ] A record with an unknown kind is refused with its line number
  • [ ] Adding a fifth kind touches only the new file and the creation point
  • [ ] Multiplication by a fractional rate rounds exactly as documented (test the half-unit case)

13. Documentation checklist

  • [ ] The pay rules for each kind, as a specification, with a worked example each
  • [ ] The money type: representation, rounding rule, and why integers
  • [ ] The class diagram, with the reuse relationship shown and justified in one sentence
  • [ ] The employee file format
  • [ ] The reconciliation evidence, pasted from a real run

14. Self-evaluation rubric

Criterion Excellent looks like Weight
Pay-rule design Kinds polymorphic; the fourth kind's reuse decided and defended 25%
Money correctness Integer arithmetic; rounding documented and tested at the boundary 25%
Reconciliation Totals equal the sum of the parts, demonstrated 15%
Separation Deductions and year-to-date data outside the employee types 15%
Failure handling Bad rates, kinds and records all refused with context 10%
Documentation Rules, representation and evidence written down 10%

Related: Intermediate projects · Project roadmap · All projects · Module 6 — Inheritance