Collections Using Base Class Pointers

The conversion from a derived class pointer to a base class pointer is very useful. For example, if you have a function that expects a pointer to an Employee as a parameter, you can pass this function a pointer to any type of employee.

One application of this is to maintain a collection of employees. You could write an EmployeeList class that maintains a linked list, each node holding a pointer to an Employee object. For example:

class EmployeeList

{

public:

EmployeeList();

add( Employee *newEmp );

// ...

private:

// ...

};

Using the add function, you can insert any type of employee into an EmployeeList object:

EmployeeList myDept;

WageEmployee *wagePtr;

SalesPerson *salePtr;

Manager *mgrPtr;

// Allocate new objects

wagePtr = new WageEmployee( "Bill Shapiro" );

salePtr = new SalesPerson( "John Smith" );

mgrPtr = new Manager( "Mary Brown" );

// Add them to the list

myDept.add( wagePtr );

myDept.add( salePtr );

myDept.add( mgrPtr );

Once you have a list of employees, you can manipulate its contents using the Employee class's interface, even though it contains all different types of employees. For example, you can define an iterator class called EmpIter (like the one described in Chapter 6), which can return each element of an EmployeeList. Then you can print a list of all the employees' names as follows:

void printNames( EmployeeList &dept )

{

int count = 0;

Employee *person;

EmpIter anIter( dept ); // Iterator object

while( person = anIter.getNext() )

{

count++;

cout << count << ' '

<< person->getName() << '\n';

}

}

This function iterates through all the elements in the EmployeeList object passed as a parameter. For each employee in the list, no matter what type it is, the iterator returns an Employee pointer. Using this pointer, the function prints out the employee's name.

The problem with this technique is that you cannot treat an object as anything more than a generic Employee. For instance, how could you compute the weekly salary of each employee in the list? If you were to give the Employee class a computePay function, calling that function wouldn't invoke the computePay functions defined in the derived classes. As mentioned earlier, the function that is called is determined by the type of the pointer. Accordingly, calling computePay using only Employee pointers would perform the same computation for every type of employee, which is clearly unsatisfactory.

What you need is a way to call each class's individual version of computePay while still using generic Employee pointers. C++ provides a way to do this using virtual functions.