160 likes | 295 Views
Polymorphism. Static & Dynamic Binding Virtual Functions Abstract & Concrete Classes Overloading & Overriding. Class Pear & Truffle. class Pear { protected: int a,b; public: Pear(int x=0, int y=0): a(x),b(y){} int add(){return a+b;} friend ostream &operator<<
E N D
Polymorphism • Static & Dynamic Binding • Virtual Functions • Abstract & Concrete Classes • Overloading & Overriding
Class Pear & Truffle class Pear { protected: int a,b; public: Pear(int x=0, int y=0): a(x),b(y){} int add(){return a+b;} friend ostream &operator<< (ostream &apple,const Pear &p) {apple<<p.a<<”, ”<<p.b; return apple;} }; class Truffle:public Pear{ int c; public: Truffle(int x=0, int y=0, int z=0) :Pear(x,y), c(z){ } int add() {return Pear::add()+c;} friend ostream & operator<< (ostream & banana, const Truffle & t){ Pear p = static_cast<Pear>(t); banana<<p<<", "<<t.c; return banana; } };
Problem • The add function for Pear will be called instead of the add function for Truffle • See truffle.cpp int main(){ Truffle t(3,4,5); Pear *ptr; ptr = &t; cout<<ptr->add()<<endl; //7 return 0; }
Static Binding • Normally, which type of function gets invoked depends on the type of pointer Pear *ptr; //declares a pointer to Pear object ptr->add(); //calls the Pear add function • This is due to static binding, which means we identify which function to call at compile time • We would like this decision to be made during execution • Look at what type of object the pointer points to • Call the appropriate function based on this type
Dynamic Binding • Virtual functions allow derived classes to have their own version of the base class functions • The system uses dynamic binding (or “late binding”) to determine which version of the function to invoke at runtime Truffle t(3,4,5); //declares Truffle object Pear *ptr; //declares pointer to Pear object ptr = &t; //pointer points to Truffle object cout<<ptr->add(); //with dynamic binding, //this now calls the Truffle add function
Making add Function Virtual class Pear { protected: int a,b; public: Pear(int x=0, int y=0): a(x),b(y){} virtual int add(){return a+b;} friend ostream &operator<< (ostream &apple,const Pear &p) {apple<<p.a<<”, ”<<p.b; return apple;} }; class Truffle:public Pear{ int c; public: Truffle(int x=0, int y=0, int z=0) :Pear(x,y), c(z){ } int add() {return Pear::add()+c;} friend ostream & operator<< (ostream & banana, const Truffle & t){ Pear p = static_cast<Pear>(t); banana<<p<<", "<<t.c; return banana; } };
Problem Solved • Now the appropriate add function will be called • Based on the object that is being pointed to, instead of being based on the pointer’s class • See virtual.cpp int main(){ Truffle t(3,4,5); Pear *ptr; ptr = &t; cout<<ptr->add()<<endl; //12 return 0; }
Class Exercise 1 • On program on next slide • What is the output if the CC class’s identity function IS declared virtual • What is the output if the CC class’s identity function IS NOT declared virtual • See version1.cpp& version2.cpp
class CC { public: virtual void identity() {cout<<"Community College"<<endl;} }; class Kapiolani:public CC { public: void identity() {cout<<"Kapiolani Community College"<<endl;} }; class Honolulu:public CC { public: void identity() {cout<<"Honolulu Community College"<<endl;} }; void main(){ CC *schools[2]; schools[0] = new Kapiolani(); schools[1] = new Honolulu(); for(inti=0;i<2;i++) schools[i]->identity(); CC c; c.identity(); Kapiolani k; k.identity(); c=k; c.identity();}
Virtual Functions • A function is virtual if • It is declared virtual • Or, there is a base class function with the same signature that is declared virtual • Signature • Consists of function’s name plus the types and counts of all the parameters of the function
Polymorphism • Polymorphism • The ability of objects of different classes related by inheritance to respond differently to the same member function call • To implement polymorphism, we need both • Virtual functions • Dynamic binding
Example • See binOp.cpp • Uses nodes of different classes to create a syntax tree to evaluate an arithmetic expression • Class hierarchy • Class Node has children BinOp & Data • Class BinOp has children Plus & Times • All have function eval()
Abstract & Concrete Class • Abstract class (or abstract base class) • Cannot instantiate objects from this kind of class (but pointers are OK) • A class is made abstract by declaring one or more of its virtual functions “pure” by setting the function equal to zero virtual void identity() = 0; • Concrete class • Can instantiate objects from this kind of class
Example class CC { public: virtual void identity()=0; }; class Kapiolani:public CC { public: void identity(){ cout<<"Kapiolani Community College"<<endl;} }; class Honolulu:public CC { public: void identity(){ cout<<"Honolulu Community College"<<endl;} }; void main(){ CC *ptr = new Kapiolani(); Honolulu h; CC *ptr2 = &h; CC c; //error (See abstract.cpp)
Overloading • Two or more functions with same name, but different signatures void classA::f (int, double) void classA::f (char, int) void classB::f (char, char) • Uses static binding • Identify which function to call at compile time • classA *x = new classB; • x->f (int, double) will call classA’s function f (int, double) • x->f (char, char) will be an error (classA does not have this function)
Overriding • Same name and same signature, but one or more base & one or more derived classes • void classA::f(int) • void classB::f(int) • Uses dynamic binding • Identify which function to call at run time • classA *x = new classB; • x->f (int) will call classB’s function f (int)