20-CS-122-001 Computer Science II Spring 2012
Inheritance: Employee Data Base

Virtual functions, classes, inheritance, lists, queues, stacks, applications

Prev      Next      Lectures      Java version      Source

// Virtual Functions and Multiple Inheritance:
// use pointers to functions to achieve generality in EmployeeList class
// See the EmployeeList class and the six functions above "main" for
// more details.

#include <stdlib.h>
#include <iostream>
#include <string.h>
using namespace std;

class Cell {
 friend class List;
   
   void *data;
   Cell *next;
   
 public:
   Cell (void *dat, Cell *nxt) {
      data = dat;
      next = nxt;
   }
};

class List {
 protected:
   Cell *head;
   Cell *tail;

   Cell *next (Cell *current) { return current->next; }
   void *objectOf (Cell *cell) { return cell->data; }

 public:
   List () { head = tail = NULL; }
   
   void enqueue (void *t) { 
      if (head == NULL) {
         head = tail = new Cell(t, NULL);
         return;
      }
      tail->next = new Cell(t, NULL);      
      tail = tail->next;
   }
};

class Employee {
   char name[30];
   
 public:
   Employee() {}
   
   Employee (const char *nm) { strcpy(name,nm); }
   
   char *getName() { return name; }
   
   virtual float computePay() const = 0;          // pure virtual
   
   virtual void display () {}
   
   virtual void setHours(void *hrs) {}
   
   virtual void setSales(void *sales) {}
   
   virtual void setSalary(void *salary) { cout << "NO!\n"; }
};

// The EmployeeList class is quite general because it assumes nothing   
// about the Employee objects or derivatives.  It anticipates the         
// need to "find" an object and provides a method for doing that but      
// makes no assumption about how an Employee object is matched with      
// a finding object - it only assumes that a function pointed to by      
// "compare" exists and "compare" has two arguments (Employee object      
// and void *object) and returns a value of 1 if and only if the         
// Employee object and void *object match somehow.  The "compare"         
// pointer is set when the constructor is called.  If "finding" should   
// change in the future, this code doesn't - instead a new "compare"      
// function is passed into the constructor.                              
//
// In addition to "find" this class supplies "findAndExecute" and         
// "executeOnAll" methods.  The "findAndExecute" applied a given         
// function of one argument to an Employee object that is "found" to      
// match a given void *object.  The "executeOnAll" method applies a      
// given function of one argument to every Employee object in the list.   
// As before, no assumptions about Employee objects are made.
class EmployeeList : public List {
   int (* compare)(Employee *, const void*);
   
 public:
   // Assign the compare pointer to a given compare function.
   EmployeeList(int (*c)(Employee *, const void*)) : List () { compare = c; }

   // Return the Employee object which matches the specified    
   // void *object of the argument list based on the "compare"   
   // function.  Return NULL if no match is found.
   Employee *find (const void *object) {
      for (Cell *emp = head ; emp != NULL ; emp = next(emp))
         if ((compare)((Employee *)(objectOf(emp)), object))
            return (Employee *)objectOf(emp);
      return NULL;
   }

   // Find an Employee matching "object" and apply function f.
   void findAndExecute (const void *object, void (*f)(Employee *, void *), void *arg) {
      f(find(object), arg);
   }

   // Apply function f to all Employee objects.
   void *executeOnAll (void (*f)(Employee *, void *), void *arg) {
      for (Cell *emp = head ; emp != NULL ; emp = next(emp))
         (f)((Employee *)objectOf(emp), arg);
      
      return arg;
   }
};

class WageEmployee : public Employee {
   float rate;
   float hours;

 public:
   WageEmployee(const char *nm) : Employee(nm) {}
   
   WageEmployee(const char *nm, float r) : Employee(nm) { rate = r; }
   
   void setRate(float r)    { rate  = r; }
   
   void setHours (float hrs) { hours = hrs; }
   
   float getHours() { return hours; }
   
   float getRate() { return rate; }
   
   float computePay() const { return rate*hours; }
};

class Programmer : public WageEmployee {
 public:
   Programmer (const char *nm, float w) : WageEmployee(nm, w) { }
   
   void display() {
      cout << "Programmer Name: " << Employee::getName()
           << "\tHours: " << WageEmployee::getHours()
           << "\tRate: "  << WageEmployee::getRate() << "\n";
   }
};

class SalesPerson : public WageEmployee {
   float commission;
   float SalesMade;
   
 public:
   SalesPerson (const char *nm, float c) : WageEmployee (nm) {
      commission = c;
   }
   
   void setCommission(float comm) { commission = comm; }
   
   void setSales (float sales) { SalesMade = sales; }
   
   float computePay() const { return commission*SalesMade; }
   
   void display() {
      cout << "Salesperson Name: " << Employee::getName()
           << "\tCommission: " << commission
           << "\tSales: "      << SalesMade << "\n";
   }
};

class Manager : public Employee {
   float monthlysalary;
   
public:
   Manager (const char *nm) : Employee (nm) { }
   
   Manager(const char *nm, float w) : Employee(nm) { monthlysalary = w; }
   
   float computePay() const { return monthlysalary; }

   void setSalary (float salary) { monthlysalary = salary; }
   
   void display() {
      cout << "Manager Name: " << Employee::getName()
           << "\tMonthly Salary: " << monthlysalary << '\n';
   }
};

// Multiple Inheritance
class SalesManager : public SalesPerson, public Manager {
public:
   SalesManager(const char *nm, float w) : SalesPerson(nm, w), Manager (nm) {}
   
   float computePay() const { // A must or else computePay() ambiguous
      return SalesPerson::computePay() + Manager::computePay();
   }
   
   void display() {
      SalesPerson::display();
      Manager::display();
   }
};

// These are all the functions that get passed into objects of the      
// EmployeeList class.  The first three are used to set local state      
// of an Employee object (used in findAndExecute(..) method).  The      
// next two are used when something needs to be done to all employees   
// (used in executeOnAll(..) method).  The last one is the compare      
// function.  In this simple example we compare only on "name" but it   
// is possible to compare on other things such as social security #      
// in future versions without changing existing code.
void setSales (Employee *emp, void *sales) {
   if (emp != NULL) ((SalesPerson *)emp)->setSales(*(float *)sales);
}
   
void setSalary (Employee *emp, void *salary) {
   if (emp != NULL) ((Manager *)emp)->setSalary(*(float *)salary);
}
   
void setHours (Employee *emp, void *hrs) {
   if (emp != NULL) ((WageEmployee *)emp)->setHours(*(float *)hrs);
}
   
void display (Employee *emp, void *null) {
   if (emp != NULL) emp->display();
}

void payroll (Employee *emp, void *accum) {
   if (emp != NULL) *(float *)accum += emp->computePay();
}

int nameCompare(Employee *emp, const void *object) {
   if (emp != NULL) return !strcmp(emp->getName(),(char *)object);
   return 0;
}

// The main procedure - create an Employee list, add employees, change
// some values for specific employees, print out the results.
int main() {
   float loc;
   char *month[] = { "January", "February", "March", "April", "May", "June",
                     "July", "August", "September", "October", "November",
                     "December" };

   EmployeeList *emp = new EmployeeList(nameCompare);
   emp->enqueue(new SalesManager("Gee", 1000));
   emp->enqueue(new SalesManager("Gal", 1000));
   emp->enqueue(new SalesManager("Gem", 1000));
   emp->enqueue(new SalesPerson("John", 0.03));
   emp->enqueue(new SalesPerson("Joan", 0.04));
   emp->enqueue(new SalesPerson("Jack", 0.02));
   emp->enqueue(new Manager("Fred", 10000));
   emp->enqueue(new Manager("Frank", 5000));
   emp->enqueue(new Manager("Florence", 3000));
   emp->enqueue(new Programmer("Linda", 7));
   emp->enqueue(new Programmer("Larry", 5));
   emp->enqueue(new Programmer("Lewis", 3));

   emp->findAndExecute("Linda", setHours, &(loc=35));
   emp->findAndExecute("Larry", setHours, &(loc=23));
   emp->findAndExecute("Lewis", setHours, &(loc=3));
   emp->findAndExecute("John", setSales, &(loc=12000));
   emp->findAndExecute("Joan", setSales, &(loc=10000));
   emp->findAndExecute("Jack", setSales, &(loc=5000));
   emp->findAndExecute("Gee", setSales, &(loc=4000));
   emp->findAndExecute("Gal", setSales, &(loc=3000));
   emp->findAndExecute("Gem", setSales, &(loc=2000));
   emp->findAndExecute("Gee", setSalary, &(loc=1000));
   emp->findAndExecute("Gal", setSalary, &(loc=2000));
   emp->findAndExecute("Gem", setSalary, &(loc=3000));

   emp->executeOnAll(display, NULL);
   cout << "Payroll: "
        << *(float *)emp->executeOnAll(payroll, &(loc=0))
        << "\n";
}