230 likes | 346 Views
EC-241 Object-Oriented Programming. LECTURE 8. Polymorphism. One interface, multiple methods C++ supports both compile time and runtime polymorphism. Example Situation That Needs Polymorphism.
E N D
EC-241 Object-Oriented Programming LECTURE 8
Polymorphism • One interface, multiple methods • C++ supports both compile time and runtime polymorphism
Example Situation That Needs Polymorphism How to write code that calls the appropriate version of draw() function with same function call? Answer: Polymorphism Shape class hierarchy Shape Circle Triangle Rectangle Right Triangle Isosceles Triangle
Polymorphism • Polymorphism is a feature of OOP that enables us to program in “general” rather than in “specific”. • Polymorphism allows us to write programs that process the objects of classes that are part of the same class hierarchy as if they were all objects of the hierarchy’s base class
Polymorphism • Polymorphism works with pointers • Pointers of base class type are used to call appropriate member functions in objects of several derived classes • This way you need to be concerned with only one type of pointers (i.e. base class pointers only) • Helping feature: Virtual functions (later)
How Polymorphism Works? • In the base class, create a virtual function Size() • In the derived classes also, create appropriate definitions of Size() • Create a base class pointer. • During execution, if sptr points to a Rectangle type object, then call to Size() will execute Rectangle’s version of Size(). • And if sptr points to a Circle type object, then call to Size() will execute Circle()’s version of Size().
How Polymorphism Works? Shape * sptr; sptr= new Rectangle(); sptr->Size(); //Rectangle’s Size sptr=new Circle(); sptr->Size(); //Circle’s Size // Notice the same call being used for different // functionalities // Important: the function Size() has to be virtual in // the base class
#include <iostream> using namespace std; class Shape { public: virtual void size() { cout<<"size of shape\n"; } };
class Circle: public Shape { public: virtual void size() { cout<<"size of circle\n"; } }; class Rectangle: public Shape { public: virtual void size() { cout<<"size of rectangle\n"; } void otherFunction() { cout<<"inside non-inherited function of derived class"; } };
void main() { Shape * sptr; sptr= new Circle(); sptr->size(); sptr=new Rectangle(); sptr->size(); //following two cases are wrong //case 1:cannot call non-inherited derived class functions through //base class pointer (except by downcasting the pointer) //sptr->otherFunction(); //case 2: cannot assign base class address to derived class pointer //Circle * c; //c= new Shape(); }
Virtual Functions • If size() was not virtual, which version would have been called? • Answer: Shape’s version • Without virtual functions, the type of the pointer determines which class’s functionality to invoke. • With virtual function, the type of the object being pointed to, not the type of the pointer , determines which version of a virtual function to invoke • Virtual functions are called through base-class pointer handles and base class reference handles, but not through name handles
Constructors and destructors • Constructors cannot be virtual. Why?? • Can we have virtual destructors. Why?? • If a class has virtual functions, provide a virtual destructor even if one is not required for the class. This ensures that a custom derived-class destructor (if there is one) will be invoked when a derived-class object is deleted via a base class pointer
Dynamic vs. Static Binding • If a program invokes a virtual function through a base class pointer to a derived class object, the program will choose the correct derived-class function dynamically (i.e. at execution time) based on the object type- not the pointer type. • Choosing the appropriate function to call at execution time is called dynamic binding (or late binding)
Dynamic vs. Static Binding • When a virtual function is called by referencing a specific object by name and using the dot operator, the function invocation is resolved at compile time (this is called static binding) and the virtual function that is called is the one defined for (or inherited by) the class of that particular object- this is not polymorphic behavior. • Thus, dynamic binding with virtual functions occurs only through pointers.
Abstract Classes • A class that cannot be instantiated • Represents general features of its sub-classes; thus can act as stereo-types • Can be used as a common interface to a hierarchy of classes
Abstract Classes • Example • CD player and DVD player • Both involve an optical disk • Operations • Insert, remove, play, record, and stop such disks
Abstract Classes CDP and DVDP have an abstract base class GDP
Abstract Classes • A class is made abstract by including at least one pure virtual function • A pure virtual function does not have an implementation, and has a =0 in its signature • A subclass of an abstract class is also abstract if it does not provide implementations for all the pure virtual functions in the superclass • A class that has all its member functions pure virtual is called an interface
Abstract Base Class – Example in C++ class Shape // abstract base class { public: virtual void move(int dx, int dy) =0;// pure //virtual function virtual void show() const =0; // pure //virtual function };
Abstract Base Class – Example contd. class Circle : public Shape // concrete class { intxcenter,ycenter,radius; public: Circle(intxc, intyc, int r) : xcenter(xc), ycenter(yc), radius(r) {} void move(intdx, intdy) { xcenter += dx; ycenter += dy; } void show() const { cout <<"Circle centered at ("<<xcenter<<","<<ycenter<<") with radius " <<radius<<"."<<endl; } };
Abstract Base Class – Example contd. class Square : public Shape // concrete class { intxll,yll,xur,yur; public: Square(int x1, int y1, int x2, int y2) : xll(x1), yll(y1), xur(x2), yur(y2) {} void move(intdx, intdy) { xll += dx; yll += dy; xur += dx; yur += dy; } void show() const { cout <<"Square with lower left corner at ("<<xll<<","<<yll <<") and upper right corner at ("<<xur<<","<<yur<<")."<<endl; } };
Abstract Base Class – Example contd. void main() { // Shape s; // compiler error, Shape is abstract Circle c(10,20,5); Square s(0,0,15,10); Shape *array[2]={&c,&s}; cout <<"Before move:"<<endl; for (inti=0; i<2; i++) array[i]->show(); for (inti=0; i<2; i++) array[i]->move(5,-5); cout <<endl<<"After move:"<<endl; for (inti=0; i<2; i++) array[i]->show(); }