Understanding Polymorphism, Static and Dynamic Binding in C++ with Examples
This document explores key object-oriented programming concepts in C++, focusing on polymorphism, static and dynamic binding, and the use of virtual functions. It illustrates how the `Pear` and `Truffle` classes utilize these principles through method overloading and overriding. By demonstrating how static binding calls the base class function while dynamic binding invokes the derived class function at runtime, it highlights the importance of virtual functions. The provided examples clarify abstract and concrete classes, showcasing how polymorphism allows for flexible and responsive code design.
Understanding Polymorphism, Static and Dynamic Binding in C++ with Examples
E N D
Presentation Transcript
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)