CSC270 Tutorial: C++ Inheritance and Virtual Functions
Inheritance
One class can be built upon another. For example, in the current
simulation assignment the Event class serves as a basis for the
following classes: TrainDepartureEvent, TrainAdvanceEvent,
TrainSwitchCheckingEvent, PassengerAppearanceEvent, and ReportEvent.
class Event {
friend class Scheduler;
protected:
float time; // time of event
virtual void handleEvent() {} // function to handle the event
};
An Event has a time and a function handleEvent().
The word "protected" means that the components of Event are visible to
only those classes derived from Event. If it were "public", all class
could see the components, while if it were "private", no classes
(including derived classes) could see the components.
Virtual Functions
handleEvent() is a "virtual function", which means that its code can
be redefined in classes that are derived from the Event class.
The PassengerAppearanceEvent class is derived from the Event class.
We say that PassengerAppearanceEvent "inherits" the components of the
Event class. Event is the "base class" and PassengerAppearanceEvent
is the "derived class".
class PassengerAppearanceEvent : public Event {
Passenger *passenger;
Station *station;
public:
PassengerAppearanceEvent( float eventTime, Passenger *p, Station *s ) {
time = eventTime;
passenger = p;
station = s;
}
void handleEvent();
};
The syntax used above indicates that PassengerAppearanceEvent is
derived from Event. The "public" keyword before "Event" indicates
that public components of Event are also public in
PassengerAppearanceEvent. That is, they are visible from outside
PassengerAppearanceEvent. However, protected components of Event are
NOT public in PassengerAppearanceEvent. We could also use the
"private" keyword, in which case public components of the base class
would be private components of the derived class and would not be
visible outside the derived class. If not keyword is present,
"private" is assumed.
The constructor above shows that, when created, a
PassengerAppearanceEvent event stores the event time, the passenger
who appears, and the station at which the passenger appears. The
PassengerAppearanceEvent class has all the variables of its base class
(i.e. time), in addition to its own variables (i.e. passenger and
station).
Usefulness of virtual functions
The virtual function is very useful. We can maintain an array
containing pointers to different types of events without knowing
exactly what types they are:
Event* events[100];
Since we know that all Events have a time and a handleEvent()
function, we can find the event of minimum time and `handle' it,
regardless of the actual type of the event.
min = 0;
for (i=1; i<100; i++) // find the event of minimum time
if (events[i]->time < events[min]->time)
min = i;
events[min]->handleEvent(); // handle it
Note that the handleEvent() function called above will be different
for the different types of Event. That is, PassengerAppearanceEvent
has one version of handleEvent(), TrainDepartureEvent (which is
derived from Event) has another version, and ReportEvent (also derived
from Event) has yet another version. C++ uses a technique called
"dynamic binding" to determine, during execution, what version of the
function to execute. This is all hidden from the programmer.