Course Name: High Level Programming Language Year : 2010 Polymorphism Lecture 10 Learning Outcomes At the end of this lecture, students are capable of: Understanding the concept of Polymorphism in C++ programming. 3 Outline Materi • • • • Polymorphism Abstract Base Classes Virtual Function Pure Virtual Function 4 Base and Derived Pointers vehicle motorcycle car truck • Base class pointers can point to derived class objects • E.g., all trucks are vehicles, so a vehicle pointer can point to a truck. • Derived class pointers cannot point to base class objects – Not all vehicles are trucks, so a truck pointer cannot point to a vehicle. Base and Derived Pointers class truck : public vehicle { protected: int capacity; }; class vehicle { protected: char type[50]; }; class car : public vehicle { protected: int numPassengers; }; class bicycle : public vehicle { protected: int serialNum; }; Base and Derived Pointers 2 void main() { vehicle *v; bicycle *b; truck *t = new truck(); v = t; // b = v; (WRONG) car *c = new car(); v = new bicycle(); delete t; delete c; delete v; } Polymorphism • Method to allow programs to generically process objects • Don’t have to know all about derived classes in advance • Good for modular reusable code – Generic linked lists, a queue of different types of people, etc. Object Polymorphism • A method expecting a Car object can only accept Car objects • A method expecting Vehicle objects can accept any object derived from the Vehicle class •Car •Truck •Bus • There’s also function polymorphism Polymorphism 2 • Normally, when an object or pointer to an object calls a function, it does so statically – I.e., determined at compile time • Another way is to allow for it to be DYNAMIC, and determined at run-time • This allows you to treat objects generically, provided they have the same interface – This is called polymorphism • How do we do this? Base classes with virtual functions. Virtual Function • A virtual function is a member function – declared within a base class – redefined by a derived class (i.e. overriding) • It can be used to support run-time polymorphism. Example class base { public: int i; base (int x) { i = x; } virtual void func() {cout << i; } }; Example class derived : public base { public: derived (int x) : base (x) {} // The keyword virtual is not needed. void func() {cout << i * i; } }; Example int main() { base ob(10), *p; derived d_ob(10); p = &ob; p->func(); p = &d_ob; p->func(); } // use base’s func() // use derived’s func() Pure Virtual Functions • A pure virtual function has no definition relative to the base class. • Only the function’s prototype is included. • General form: virtual type func-name(paremeter-list) = 0 Example: area class area { public: double dim1, dim2; area(double x, double y) {dim1 = x; dim2 = y;} // pure virtual function virtual double getarea() = 0; }; Example: rectangle class rectangle : public area { public: // function overriding double getarea() { return dim1 * dim2; } }; Example: triangle class triangle : public area { public: // function overriding double getarea() { return 0.5 * dim1 * dim2; } }; Facts about Virtual Functions • When a virtual function is called, the computer determines at runtime the appropriate derived function to execute. • The base class has the virtual functions • New derived classes can be added that implement their own versions of these functions • Override the base virtual functions in derived classes! More Example of Virtual Functions class person { protected: char *name; char *phone; public: person(char *n, char *p); virtual void print(); }; class student : public person { protected: int studentID; public: student(int id); void print(); }; class teacher : public person { protected: int deptID; public: teacher(int d); void print(); }; Virtual Functions Example 2 void person::print() { cout << name << “ “ << phone << endl; } void student::print() { cout << “Student” << endl; cout << “ID: “ << studentID << endl; cout << name << endl << phone << endl; } void teacher::print() { cout << “Teacher” << endl; cout << “Dept: “ << deptID << endl; cout << name << endl << phone << endl; } Virtual Functions Example 3 void main() { int x; person **array = new person*[3]; array[0] = new student(“Joe”, “555-1234”, 3976); array[1] = new teacher(“Daisy”, “555-8909”, 203); array[2] = new person(“Mandy”, “555-3782”); for (x = 0; x < 3; x++) array[x]->print(); } More Virtual Functions • Without virtual functions, only the base class print() function would be called • This is because all the pointers are of the base type • WITH virtual functions, the correct print function is called for each member of the array – array[0]->print() calls student::print() – array[1]->print() calls teacher::print() – array[2]->print() calls person::print() What does this mean? • It means that you don’t necessarily have to know the EXACT type of the object you’re dealing with • You only have to know it’s base type • Base classes & base class interfaces written by someone else long ago can work with new classes you write Abstract Base Classes • Sometimes you will NEVER WANT TO instantiate an object of the base class. • E.g., doesn’t make sense to make a shape object – Only a square object, a circle object, or some other derived object actually makes sense… • Can make the class abstract so that future programmers cannot create a base class object either Implementing Pure Virtual Functions • How do you make a base class abstract? • Make at least one of its member functions PURE VIRTUAL • Functions should be pure virtual if information is needed from the derived class for any valid implementation – a shape’s area function depends on what type of shape it is Review of Pure Virtual Functions • Pure virtual functions are defined in the class declaration by: virtual returnType functionName(arglist) const = 0; • So for the shape area function example, we’d have in the shape class: virtual float area() const = 0; • There is NO IMPLEMENTATION of pure virtual functions in the base class, just the declaration Virtual Destructors • Why should destructors be virtual if a base class has any virtual functions? • Derived objects will likely be accessed by base pointers • If you “delete” a base pointer without a virtual destructor, it will only call the base destructor • If virtual, however, it will call the correct derived destructor, then the base destructor Example #include <iostream.h> class base { public: virtual void vfunc() { cout<<“This is the base vfunc().\n”; } }; class derived1 : public base { public: virtual void vfunc() { cout<<“This is a derived function\n”;} }; class derived2 : public base { public: virtual void vfunc() { cout<<“So is this one.\n”; } }; Example in Action int main() { base* p; base b; derived1 d1; derived2 d2; A pointer to the parent class p=&b; p->vfunc(); p=&d1; p->vfunc(); p=&d2; p->vfunc(); } OUTPUT: This is a base vfunc(). This is a derived function. So is this one. Other Examples of Polymorphism • Queue of jobs to do – Homework – Cleaning – Cooking • Linked list of classes – Lectures – Labs – Discussion sections Conclusion for Virtual Functions • A virtual function is a member function that is declared within a base class and redefined by a derived class. • Its looks just like a normal function but has the keyword virtual preceding it. • So the virtual function defines the form of the interface. • The derived class redefines it and implements its operation as it relates specifically to it. Why Virtual Functions are Useful (concluded) • So you can just use virtual functions as you would any other function. • However what makes them so implortant is how they behave when accessed by a pointer. • When a base-class pointer points to a derived object that contains a virtual function, C++ decides which version of that function to call – based on the type of object pointed to. • This is all processed at run-time. Conclusion of Abstract Classes • A class that contains at least one pure virtual function is said to be abstract – it has a virtual function in it that has no definition at all. • Because of this, no objects of the abstract class can be created. • It is an incomplete type – a foundation for derived classes. • However you can still create a pointer to an abstract class. Conclusion of Polymorphism • An object can take many forms. – Method overloading is one type of polymorphism. – Object polymorphism treats specialized objects as if they are instances of a more general type. More on Factoring to the Base Class • Factor common characteristics of multiple classes up into a base class. – HWall and VWall classes have similar characteristics and methods. – Factor commonalities to a Wall class – Override some methods to specialize the HWall and VWall classes Conclusion of Abstract Base Classes • The classes describe what all derived classes have in common. – Not instantiated (causes an exception) – Use the abstract keyword when defining abstract base classes and methods Conclusion For Abstract Methods – Abstract methods are not implemented. – Derived classes must provide method implementation. Topic For Next Week • Template • Assignment: Read chapter 9 of C++Essentials.pdf, and then do the following exercise: Define a swap function template for swapping two objects of the same type! 39