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.