CSC270 November 11 Tutorial: C++


Inheritance and Virtual Functions

One class can be built upon another. For example, in the current simulation assignment the Event class serves as a basis for the PersonAppearance, ElevatorArrival, and ElevatorDeparture events. class Event { protected: float time; // time of event virtual void handle_event() // function to handle the event {} }; An Event has a time and a function handle_event(). 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. handle_event() is a "virtual function", which means that its code can be redefined in classes that are derived from the Event class. The PersonAppearance class is derived from the Event class. We say that PersonAppearance "inherits" the components of the Event class. Event is the "base class" and PersonAppearance is the "derived class". class PersonAppearance : public Event { public: // the constructor PersonAppearance( float event_time, Floor *source, Floor *dest ) time = event_time; source_floor = source; dest_floor = dest; } // a definition for the virtual function void handle_event() { Person *person; person = new Person; person->handle_initial_appearance( source_floor, dest_floor ); source_floor->schedule_next_appearance(); } private: Floor *source_floor; Floor *dest_floor; }; The syntax used above indicates that PersonAppearance is derived from Event. The "public" keyword before "Event" indicates that public components of Event are also public in PersonAppearance. That is, they are visible from outside PersonAppearance. However, protected components of Event are NOT public in PersonAppearance. 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. The constructor above shows that, when created, a PersonAppearance event stores the event time, the floor upon which the person appears (source) and the floor to which the person wants to go (dest). The PersonAppearance class has all the variables of its base class (i.e. time), in addition to its own variables (i.e. source_floor and dest_floor).

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 handle_event() 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]->handle_event(); // handle it Note that the handle_event() function called above will be different for the different types of Event. That is, PersonAppearance has one version of handle_event(), ElevatorArrival (which is derived from Event) has another version, and ElevatorDeparture (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.