Inheritance Polymorphism Computer Science Department OOP Concepts Objects
Inheritance & Polymorphism Computer Science Department
OOP Concepts • Objects and Classes / Data Encapsulation • Inheritance • Polymorphism – Operator overloading is a kind of polymorphism Computer Science Department CPS 235: Polymorphism 2
Polymorphism • A function/operator can behave differently depending on the context in which it is called • We have already seen operator overloading in which a single ‘+’ operator behaves differently when used with floats, ints or strings • Polymorphism refers to the ability of similar objects to respond differently to the same message i. e. , the same type of function call • Selecting the correct function is deferred until runtime and is based on the object Computer Science Department CPS 235: Polymorphism 3
Upcasting • Inheritance represents an “is-a” relationship – The new class is a type of the existing class enum note { middle. C, Csharp, Cflat }; class Instrument { public: void play(note) const {} }; // Wind objects are also Instruments class Wind : public Instrument {}; void tune(Instrument& i) { //. . . i. play(middle. C); } int main() { Wind flute; tune(flute); // Upcasting } Computer Science Department CPS 235: Polymorphism 4
Upcasting (contd. . ) • A Wind object is also an Instrument object, and there’s no function that tune( ) could call for an Instrument that isn’t also in Wind • Inside tune( ), the code works for Instrument and anything derived from Instrument, and the act of converting a Wind object, reference, or pointer into an Instrument object, reference, or pointer is called upcasting Computer Science Department CPS 235: Polymorphism 5
Pointer and Reference Upcasting Wind w; Instrument* ip = &w; // Upcast Instrument& ir = w; // Upcast • Of course, any upcast loses type information about an object. If you say Wind w; Instrument* ip = &w; • the compiler can deal with ip only as an Instrument pointer and nothing else i. e. , it cannot know that ip actually points to a Wind object • So when you call the play( ) member function by saying ip->play(middle. C); • the compiler can know only that it’s calling play( ) for an Instrument pointer, and call the base-class version of Instrument: : play( ) instead of what it should do, which is call Wind: : play( ) Computer Science Department CPS 235: Polymorphism 6
Problem with upcasting enum note { middle. C, Csharp, Cflat }; class Instrument { public: void play(note) const { cout << "Instrument: : play" << endl; } }; class Wind : public Instrument { public: void play(note) const { cout << "Wind: : play" << endl; } }; void tune(Instrument& i) { //. . . i. play(middle. C); } int main() { Wind flute; tune(flute); // Upcasting } Computer Science Department CPS 235: Polymorphism 7
Problem with upcasting • The output of the previous program is Instrument: : play • This is clearly not the desired output, because you know that the object is actually a Wind and not just an Instrument – The call should resolve to Wind: : play • The above discussion also applies if you use a pointer to an Instrument in the function tune Computer Science Department CPS 235: Polymorphism 8
Function call binding • Connecting a function call to a function body is called binding • When binding is performed before the program is run (by the compiler and linker), it’s called early binding or static binding • The problem in the above program is caused by early binding because the compiler cannot know the correct function to call when it has only an Instrument address Computer Science Department CPS 235: Polymorphism 9
Dynamic Binding • The solution to the above problem is called late binding or dynamic binding which means the binding occurs at runtime, based on the type of the object • When a language implements late binding, there must be some mechanism to determine the type of the object at runtime and call the appropriate member function • The compiler still doesn’t know the actual object type, but it inserts code that finds out and calls the correct function body • Implemented in C++ using virtual functions Computer Science Department CPS 235: Polymorphism 10
Virtual Functions • Virtual Functions enable run time object determination • Keyword virtual instructs the compiler to use late binding and delay the object interpretation • How ? – Define a virtual function in the base class. The word virtual appears only in the base class – If a base class declares a virtual function, it must implement that function, even if the body is empty – Virtual function in base class stays virtual in all the derived classes – It can be overridden in the derived classes • But, a derived class is not required to re-implement a virtual function. If it does not, the base class version is used Computer Science Department CPS 235: Polymorphism 11
Virtual Functions enum note { middle. C, Csharp, Cflat }; class Instrument { public: virtual void play(note) const { cout << "Instrument: : play" << endl; } }; class Wind : public Instrument { public: void play(note) const { cout << "Wind: : play" << endl; } }; void tune(Instrument& i) { //. . . i. play(middle. C); } int main() { Wind flute; tune(flute); // prints Wind: : play } Computer Science Department CPS 235: Polymorphism 12
Extensibility • With play( ) defined as virtual in the base class, you can add as many new types as you want to the system without changing the tune( ) function • Such a program is extensible because you can add new functionality by inheriting new data types from the common base class • The functions that manipulate the base-class interface will not need to be changed at all to accommodate the new classes Computer Science Department CPS 235: Polymorphism 13
Extensibility enum note { middle. C, Csharp, Cflat }; class Instrument { public: virtual void play(note) const { cout << "Instrument: : play" << endl; } virtual char* what() const { return "Instrument"; } virtual void adjust(int) {} }; class Wind : public Instrument { public: void play(note) const { cout << "Wind: : play" << endl; } char* what() const { return "Wind"; } void adjust(int) {} }; Computer Science Department CPS 235: Polymorphism 14
class Percussion : public Instrument { public: void play(note) const { cout << "Percussion: : play" << endl; } char* what() const { return "Percussion"; } void adjust(int) {} }; class Stringed : public Instrument { public: void play(note) const { cout << "Stringed: : play" << endl; } char* what() const { return "Stringed"; } void adjust(int) {} }; class Brass : public Wind { public: void play(note) const { cout << "Brass: : play" << endl; } char* what() const { return "Brass"; } }; Computer Science Department CPS 235: Polymorphism 15
class Woodwind : public Wind { public: void play(note) const { cout << "Woodwind: : play" << endl; } char* what() const { return "Woodwind"; } }; void tune(Instrument& i) { //. . . i. play(middle. C); } int main() { Wind flute; Percussion drum; Stringed violin; Brass flugelhorn; Woodwind recorder; tune(flute); tune(drum); tune(violin); tune(flugelhorn); tune(recorder); } Computer Science Department CPS 235: Polymorphism 16
Virtual functions work only with addresses (references / pointers) class Base { public: virtual int f() const { return 1; } void g()const { cout<<“Base”; } }; class Derived : public Base { public: int f() const { return 2; } void show(){ cout<<“derived only”; } void g() { cout<<“derived”; } }; Computer Science Department CPS 235: Polymorphism 17
Virtual functions work only with addresses (references / pointers) void main() { Derived d; Base* b 1 = &d; Base& b 2 = d; Base b 3; // Late binding: cout << "b 1 ->f() = " << b 1 ->f() << endl; cout << "b 2. f() = " << b 2. f() << endl; // Early binding: cout << "b 3. f() = " << b 3. f() << endl; cout<<“b 1 ->g() = ” ; b 1 ->g(); cout<<endl; cout<<“b 1 ->show()=”; b 1 ->show(); } Computer Science Department CPS 235: Polymorphism 18
Arrays of Pointers to Objects class Base { public: virtual void show() { cout<<"base“; } }; class Derv 1 : public Base { public: void show() { cout<<"derv 1“; }; class Derv 2 : public Base { public: void show() { cout<<"derv 2“; } }; Computer Science Department CPS 235: Polymorphism void main() { Base* array[2]; Derv 1 d 1; Derv 2 d 2; array[0] = &d 1; array[1] = &d 2; for(int i=0; i<2; i++) array[i]->show(); getch(); } 19
Object Slicing If you use an object instead of a pointer or reference as the recipient of your upcast, the object is “sliced” class Base { int i; public: Base(int ii = 0) : i(ii) {} virtual int sum() const { return i; } }; class Derived : public Base { int j; public: Derived(int ii = 0, int jj = 0): Base(ii), j(jj) {} int sum() const { return Base: : sum() + j; }}; Computer Science Department void call(Base b) { cout << "sum = " << b. sum() << endl; } int main() { Base b(10); Derived d(10, 47); call(b); call(d); } CPS 235: Polymorphism 20
Polymorphism Summary • When you use virtual functions, compiler stores additional information about the types of object available and created • Polymorphism is supported at this additional overhead • Important : – virtual functions work only with pointers/references – Not with objects even if the function is virtual Computer Science Department CPS 235: Polymorphism 21
Abstract Classes & Pure Virtual Functions • Some classes exist logically but not physically. • Example : Shape – Shape s; // Legal but silly. . !! : “Shapeless shape” – Shape makes sense only as a base of some classes derived from it. Serves as a “category” – Hence instantiation of such a class must be prevented class Shape //Abstract { public : //Pure virtual Function virtual void draw() = 0; } § § A class with one or more pure virtual functions is an Abstract Class Objects of abstract class can’t be created Shape s; // error : variable of an abstract class Computer Science Department CPS 235: Polymorphism 22
Example Shape virtual void draw() Circle Triangle public void draw() Computer Science Department CPS 235: Polymorphism 23
Abstract Classes & Pure Virtual Functions • A pure virtual function not defined in the derived class remains a pure virtual function. • Hence derived class also becomes abstract class Circle : public Shape { //No draw() - Abstract public : void print(){ cout << “I am a circle” << endl; } class Rectangle : public Shape { public : void draw(){ // Override Shape: : draw() cout << “Drawing Rectangle” << endl; } Rectangle r; // Valid Circle c; // error : variable of an abstract class Computer Science Department CPS 235: Polymorphism 24
Abstract classes • If a method is to be over-ridden by each child class, we can enforce this policy through the use of abstract classes • You can’t create an object of an abstract class ( a class with at least one pure virtual function) • You can also not pass or return an object of an abstract class by value Computer Science Department CPS 235: Polymorphism 25
Abstract classes • It is still possible to provide definition of a pure virtual function in the base class • The class still remains abstract and functions must be redefined in the derived classes, but a common piece of code can be kept there to facilitate reuse class Shape { //Abstract public : virtual void draw() = 0; }; Shape: : draw(){ cout << “Shape" << endl; } Computer Science Department class Rectangle : public Shape { public : void draw(){ Shape: : draw(); //Reuse cout <<“Rectangle”<< endl; } CPS 235: Polymorphism 26
Virtual Destructor • If any of the functions in your class are virtual, the destructor should be virtual as well class Base { public: virtual ~Base() { cout << "~Base()" << endl; } }; class Derived : public Base { public: ~Derived() { cout << "~Derived()" << endl; } }; int main() { Base* bp = new Derived; // Upcast delete bp; // Virtual destructor call } Computer Science Department CPS 235: Polymorphism 27
Things to remember • Beginning a class method declaration with the keyword virtual in a base class makes the function virtual for the base class and all derived classes, classes further derived from derived classes, and so on… • dynamic binding is possible only for a base class pointer or reference to an object of the derived class • All those functions of the base class that need to be overridden in the derived classes should be made virtual • Constructors cannot be virtual • Destructors can be virtual – You should provide a base class which has virtual functions with a virtual destructor even if the class does not need a destructor (i. e. , it does not contain dynamic data) Computer Science Department CPS 235: Polymorphism 28
Things to remember • friends can’t be virtual since they are not member functions • If a derived class does not redefine a virtual function, the base class version is used. If there is a chain of derived classes, then the most recently defined version of the virtual function is used • An abstract class demands that its pure virtual functions must be over-ridden in each derived class, otherwise the derived class also becomes abstract Computer Science Department CPS 235: Polymorphism 29
Inheritance and Dynamic Memory Allocation • If a base class uses dynamic memory allocation and redefines assignment operator and copy constructor, how does it affect the implementation of the derived class? – If the derived class does not itself use dynamic memory allocation, no special steps need to be taken – If the derived class uses dynamic memory allocation, then the assignment operator and copy constructor need to be defined for the derived class as well Computer Science Department CPS 235: Polymorphism 30
If the derived class does not use new class base { private: char* label; int rating; public: base(const char* l = "null", int r = 0); base(const base& rs); virtual ~base(); base& operator = (const base& rs); }; class lacks. DMA : public base { private: char color[40]; public: . . . }; Computer Science Department CPS 235: Polymorphism 31
If the derived class does not use new • There’s no need for defining a destructor. The default destructor will automatically call the base class destructor which will free the memory allocated in the base part of the object • There’s no need for defining a copy constructor since the default copy constructor will automatically call the base class copy constructor for copying the base part of the object • Assignment operator overloading is also not required for the same reason Computer Science Department CPS 235: Polymorphism 32
If the derived class does use new class has. DMA : public base { private: char* style; //to point to dynamic memory public: . . . }; • For this class, you will have to define destructor, copy constructor and assignment operator Computer Science Department CPS 235: Polymorphism 33
If the derived class uses new • Destructor base: : ~base() { delete [] label; } has. DMA: : ~has. DMA() { delete[] style; } Computer Science Department CPS 235: Polymorphism 34
If the derived class uses new • Copy Constructor base: : base(const base& rs) { label = new char[strlen(rs. label)+1]; strcpy(label, rs. label); rating = rs. rating; } has. DMA: : has. DMA(const has. DMA& hs) : base(hs) { style = new char[strlen(hs. style)+1]; strcpy(style, hs. style); } Computer Science Department CPS 235: Polymorphism 35
If the derived class uses new • Assignment Operator base& base: : operator=(const base& rs) { if(this==&rs) return *this; delete [] label; label = new char[strlen(rs. label)+1]; strcpy(label, rs. label); rating = rs. rating; return *this; } has. DMA& has. DMA: : operator=(const has. DMA& hs) { if(this==&hs) return *this; base: : operator=(hs); //copy base style = new char[strlen(hs. style)+1]; strcpy(style, hs. style); return *this; Computer CPS 235: Polymorphism } Science Department 36
stream operators ostream& operator<<(ostream& os, const base& rs) //declared friend in class base { os<<"Label: " <<rs. label << endl; os << "Rating: " << rs. rating << endl; return os; } ostream& operator<<(ostream& os, const lacks. DMA& rs)//declared friend in lacks. DMA { os << (const base& )rs; //type casting //lacks. DMA parameter to base argument os << "Color: " <<rs. color << endl; return os; } Computer Science Department CPS 235: Polymorphism 37
stream operators ostream& operator<< (ostream& os, const has. DMA& rs) //declared friend in has. DMA { os << (const base& )rs; //type casting //has. DMA parameter to base argument os << "Style: " <<rs. style << endl; return os; } Computer Science Department CPS 235: Polymorphism 38
Recommended Reading • Bruce Eckel’s “Thinking in C++” available online at http: //www. codeguru. com/cpp/tic_c. shtml Computer Science Department CPS 235: Polymorphism 39
How C++ implements virtual binding Computer Science Department CPS 235: Polymorphism 40
How C++ implements virtual binding Computer Science Department CPS 235: Polymorphism 41
Cost of Polymorphism • VTABLE for every polymorphic class • VPTR embedded in every polymorphic object • Indirect function access Computer Science Department CPS 235: Polymorphism 42
Another Example class Base { public: virtual void function 1() {}; virtual void function 2() {}; }; class D 1: public Base { public: void function 1() {}; }; class D 2: public Base { public: void function 2() {}; Computer Science Department CPS 235: Polymorphism 43
Computer Science Department CPS 235: Polymorphism 44
- Slides: 44