Object-Oriented Programming in C++ Lecture 7 Polymorphism Introduction Last lecture we •reviewed the concept of inheritance •discussed how to implement inheritance in C++ This lecture we will •introduce polymorphism •explain virtual and pure virtual functions •learn how to use polymorphism in C++ programs Polymorphism Vehicle • many forms • Greek +move() – "poly" – many – "morph" form LandVehicl Airplane • the same method can be called on different e +move() objects +move() • they may respond to it in different ways • all Vehicles have a Car Truck move method • Cars and Truck drive • Airplanes fly Polymorphism example • see handout for implementation of Vehicle class hierarchy #include "Vehicle.h" int main(){ Vehicle v ("Transporter 54"); Airplane a("Tornado 2431", 14); LandVehicle lv("My wheels"); Car c("Ford Anglia 22"); Truck t("Red pickup"); v.move(); a.move(); lv.move(); c.move(); t.move(); } Output Vehicle constructor Vehicle constructor Airplane constructor Vehicle constructor Land vehicle constructor Vechicle constructor Land vehicle constructor Car constructor Vechicle constructor Land vehicle constructor Truck constructor Vehicle Transporter 54 moving Airplane Tornado 2431 flying Land Vehicle My wheels driving Land Vehicle Ford Anglia 22 driving Land Vehicle Red pickup driving Which version of move is called • in the previous example, the version of move to be called was determined at compile time – depends on the object type – for Airplane a, the Airplane version of move – for Car c, the Vehicle version of move • what about a situation where the type is not known at compile time? #include "Vehicle.h" void moveVehicle(Vehicle * v) { v->move(); } int main(){ Vehicle v ("Transporter 54"); Airplane a("Tornado 2431", 14); LandVehicle lv("My wheels"); Car c("Ford Anglia 22"); Truck t("Red pickup"); moveVehicle(&v); moveVehicle(&a); moveVehicle(&lv); moveVehicle(&c); moveVehicle(&t); } Output …. Vehicle Transporter 54 moving Vehicle Tornado 2431 moving Vehicle My wheels moving Vehicle Ford Anglia 22 moving Vehicle Red pickup moving • the moveVehicle method takes a pointer to any Vehicle object • which could be any subtype of Vehicle • however, the move method to call is determined at compile time – Vehicle version • all vehicles move the same way Polymorphic behaviour • to get polymorphic behaviour, we would like the version of move() to be determined at run-time • if moveVehicle is sent an Airplane object, it should get it to fly • do this by using the virtual keyword in the first (base class) declaration of the polymorphic method class Vehicle { protected: string name; public: // other members virtual void move() { cout << "Vehicle " << name << " moving" << endl; } }; • now it works Polymorphic output Vehicle Transporter 54 moving Airplane Tornado 2431 flying Land Vehicle My wheels driving Land Vehicle Ford Anglia 22 driving Land Vehicle Red pickup driving Polymorphism • polymorphism allows us to use a pointer to a derived type object wherever a pointer to base type is expected Car c("Ford Anglia 22"); Vehicle * v2 = &c; v2->move(); Land Vehicle Ford Anglia 22 driving Land Vehicle Ford Anglia 22 driving Vehicle & v3 = c; v3.move(); • only works for pointer and reference types • they store an address – same size for all objects This won't work Airplane a("Tornado 2431", 14); Vehicle v2 = a; v2.move(); • trying to fit an airplane into a space meant for any vehicle • can call the move() method, but we've lost the wingspan member variable Virtual destructors • constructors cannot be virtual – the correct one is always called anyway • destructors can be virtual • you should specify a virtual destructor for any class which is overridden • so that the object is cleaned up correctly • otherwise you might not deallocate all the memory allocated to a subclass object Pure virtual functions • sometimes it is not sensible to implement a base class virtual function • how does a Vehicle move? • a pure virtual function does not have an implementation • virtual void move() =0; • the subclasses must implement it • a class with a pure virtual function cannot be instantiated – if we made it virtual, how would it move? • such a class is abstract Comparison to Java • in Java, all methods are virtual by default • the keyword abstract is used to define pure virtual functions • a class containing an abstract method must itself be abstract • C++ is more flexible but can be confusing – why have virtual and non-virtual functions? Virtual functions • using a virtual function has an overhead • the correct method cannot be bound to a method call at compile time • it is determined at run-time by looking up the correct method address in a table • this takes up time and space • if polymorphism is not being used, this is expensive. Summary In this lecture we have: •introduced polymorphism •explained virtual and pure virtual functions •learned how to use polymorphism in C++ programs