Transcript
Page 1: Computer Science Department Inheritance & Polymorphism

Computer Science Department

Inheritance & Polymorphis

m

Page 2: Computer Science Department Inheritance & Polymorphism

Computer Science Department

OOP Concepts• Objects and Classes / Data Encapsulation• Inheritance• Polymorphism

– Operator overloading is a kind of polymorphism

CPS235:Polymorphism 2

Page 3: Computer Science Department Inheritance & Polymorphism

Computer Science Department

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

CPS235:Polymorphism 3

Page 4: Computer Science Department Inheritance & Polymorphism

Computer Science Department

Upcasting• Inheritance represents an “is-a” relationship

– The new class is a type of the existing classenum note { middleC, Csharp, Cflat }; class Instrument {public: void play(note) const {}};// Wind objects are also Instruments

class Wind : public Instrument {};

void tune(Instrument& i) { // ... i.play(middleC);}

int main() { Wind flute; tune(flute); // Upcasting}

CPS235:Polymorphism 4

Page 5: Computer Science Department Inheritance & Polymorphism

Computer Science Department

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

CPS235:Polymorphism 5

Page 6: Computer Science Department Inheritance & Polymorphism

Computer Science Department

Pointer and Reference UpcastingWind w;Instrument* ip = &w; // UpcastInstrument& 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(middleC);

• 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( )

CPS235:Polymorphism 6

Page 7: Computer Science Department Inheritance & Polymorphism

Computer Science Department

Problem with upcastingenum note { middleC, 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(middleC);}int main() { Wind flute; tune(flute); // Upcasting }

CPS235:Polymorphism 7

Page 8: Computer Science Department Inheritance & Polymorphism

Computer Science Department

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

CPS235:Polymorphism 8

Page 9: Computer Science Department Inheritance & Polymorphism

Computer Science Department

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

CPS235:Polymorphism 9

Page 10: Computer Science Department Inheritance & Polymorphism

Computer Science Department

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

CPS235:Polymorphism 10

Page 11: Computer Science Department Inheritance & Polymorphism

Computer Science Department

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

CPS235:Polymorphism 11

Page 12: Computer Science Department Inheritance & Polymorphism

Computer Science Department

Virtual Functions enum note { middleC, 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(middleC);}int main() { Wind flute; tune(flute); // prints Wind::play}

CPS235:Polymorphism 12

Page 13: Computer Science Department Inheritance & Polymorphism

Computer Science Department

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

CPS235:Polymorphism 13

Page 14: Computer Science Department Inheritance & Polymorphism

Computer Science Department

Extensibilityenum note { middleC, 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) {}}; 

CPS235:Polymorphism 14

Page 15: Computer Science Department Inheritance & Polymorphism

Computer Science Department

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"; }}; 

CPS235:Polymorphism 15

Page 16: Computer Science Department Inheritance & Polymorphism

Computer Science Department

class Woodwind : public Wind {public: void play(note) const { cout << "Woodwind::play" << endl; } char* what() const { return "Woodwind"; }};

void tune(Instrument& i) { // ... i.play(middleC);}int main() { Wind flute; Percussion drum; Stringed violin; Brass flugelhorn; Woodwind recorder; tune(flute); tune(drum); tune(violin); tune(flugelhorn); tune(recorder);}

CPS235:Polymorphism 16

Page 17: Computer Science Department Inheritance & Polymorphism

Computer Science Department

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”; }};

CPS235:Polymorphism 17

Page 18: Computer Science Department Inheritance & Polymorphism

Computer Science Department

Virtual functions work only with addresses (references / pointers)

void main() { Derived d; Base* b1 = &d; Base& b2 = d; Base b3;

// Late binding: cout << "b1->f() = " << b1->f() << endl; cout << "b2.f() = " << b2.f() << endl;

// Early binding: cout << "b3.f() = " << b3.f() << endl;cout<<“b1->g() = ” ; b1->g(); cout<<endl;cout<<“b1->show()=”; b1->show();

}

CPS235:Polymorphism 18

Page 19: Computer Science Department Inheritance & Polymorphism

Computer Science Department

Arrays of Pointers to Objects class Base {public: virtual void show() { cout<<"base“; }};

class Derv1 : public Base{

public:void show()

{ cout<<"derv1“; };class Derv2 : public Base{

public:void show()

{ cout<<"derv2“; }

};

void main() { Base* array[2]; Derv1 d1; Derv2 d2; array[0] = &d1; array[1] = &d2; for(int i=0;i<2;i++) array[i]->show();

getch();}

CPS235:Polymorphism 19

Page 20: Computer Science Department Inheritance & Polymorphism

Computer Science Department

Object Slicing

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; }};

void call(Base b) { cout << "sum = " <<

b.sum() << endl;}

int main() { Base b(10); Derived d(10, 47); call(b); call(d);}

CPS235:Polymorphism 20

If you use an object instead of a pointer or reference as the recipient of your upcast, the object is “sliced”

Page 21: Computer Science Department Inheritance & Polymorphism

Computer Science Department

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

CPS235:Polymorphism 21

Page 22: Computer Science Department Inheritance & Polymorphism

Computer Science Department

CPS235:Polymorphism 22

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

Page 23: Computer Science Department Inheritance & Polymorphism

Computer Science Department

CPS235:Polymorphism 23

Example

Shape

virtual void draw()

Circle

public void draw()

Triangle

public void draw()

Page 24: Computer Science Department Inheritance & Polymorphism

Computer Science Department

CPS235:Polymorphism 24

• 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() - Abstractpublic :void print(){ cout << “I am a circle” << endl;}

class Rectangle : public Shape {public :void draw(){ // Override Shape::draw() cout << “Drawing Rectangle” << endl;}

Rectangle r; // ValidCircle c; // error : variable of an abstract class

Abstract Classes & Pure Virtual Functions

Page 25: Computer Science Department Inheritance & Polymorphism

Computer Science Department

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

CPS235:Polymorphism 25

Page 26: Computer Science Department Inheritance & Polymorphism

Computer Science Department

CPS235:Polymorphism 26

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;}

class Rectangle : public Shape

{ public : void draw(){ Shape::draw(); //Reuse cout <<“Rectangle”<< endl;}

Page 27: Computer Science Department Inheritance & Polymorphism

Computer Science Department

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}

CPS235:Polymorphism 27

Page 28: Computer Science Department Inheritance & Polymorphism

Computer Science Department

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 over-ridden 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)

CPS235:Polymorphism 28

Page 29: Computer Science Department Inheritance & Polymorphism

Computer Science Department

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

CPS235:Polymorphism 29

Page 30: Computer Science Department Inheritance & Polymorphism

Computer Science Department

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

CPS235:Polymorphism 30

Page 31: Computer Science Department Inheritance & Polymorphism

Computer Science Department

If the derived class does not use newclass 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 lacksDMA : public base{

private: char color[40]; public: ...};

CPS235:Polymorphism 31

Page 32: Computer Science Department Inheritance & Polymorphism

Computer Science Department

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

CPS235:Polymorphism 32

Page 33: Computer Science Department Inheritance & Polymorphism

Computer Science Department

If the derived class does use newclass hasDMA : 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

CPS235:Polymorphism 33

Page 34: Computer Science Department Inheritance & Polymorphism

Computer Science Department

If the derived class uses new• Destructor

base::~base(){

delete [] label;}

hasDMA::~hasDMA(){

delete[] style;}

CPS235:Polymorphism 34

Page 35: Computer Science Department Inheritance & Polymorphism

Computer Science Department

If the derived class uses new• Copy Constructorbase::base(const base& rs){

label = new char[strlen(rs.label)+1]; strcpy(label,rs.label); rating = rs.rating;}

hasDMA::hasDMA(const hasDMA& hs) : base(hs){

style = new char[strlen(hs.style)+1]; strcpy(style,hs.style);}

CPS235:Polymorphism 35

Page 36: Computer Science Department Inheritance & Polymorphism

Computer Science Department

If the derived class uses new• Assignment Operatorbase& 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;}hasDMA& hasDMA::operator=(const hasDMA& hs){

if(this==&hs) return *this; base::operator=(hs); //copy base style = new char[strlen(hs.style)+1]; strcpy(style,hs.style); return *this;}

CPS235:Polymorphism 36

Page 37: Computer Science Department Inheritance & Polymorphism

Computer Science Department

stream operatorsostream& 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 lacksDMA& rs) //declared friend in lacksDMA

{os << (const base& )rs; //type casting //lacksDMA parameter to base argument

os << "Color: " <<rs.color << endl; return os;}

CPS235:Polymorphism 37

Page 38: Computer Science Department Inheritance & Polymorphism

Computer Science Department

stream operatorsostream& operator<< (ostream& os, const hasDMA& rs) //declared friend in hasDMA

{os << (const base& )rs; //type casting //hasDMA parameter to base argument

os << "Style: " <<rs.style << endl; return os;}

CPS235:Polymorphism 38

Page 39: Computer Science Department Inheritance & Polymorphism

Computer Science Department

Recommended Reading• Bruce Eckel’s “Thinking in C++” available online

athttp://www.codeguru.com/cpp/tic/tic_c.shtml

CPS235:Polymorphism 39

Page 40: Computer Science Department Inheritance & Polymorphism

Computer Science Department

How C++ implements virtual binding

CPS235:Polymorphism 40

Page 41: Computer Science Department Inheritance & Polymorphism

Computer Science Department

How C++ implements virtual binding

CPS235:Polymorphism 41

Page 42: Computer Science Department Inheritance & Polymorphism

Computer Science Department

Cost of Polymorphism• VTABLE for every polymorphic class• VPTR embedded in every polymorphic object• Indirect function access

CPS235:Polymorphism 42

Page 43: Computer Science Department Inheritance & Polymorphism

Computer Science Department

Another Exampleclass Base { public: virtual void function1() {}; virtual void function2() {}; };   class D1: public Base { public:     void function1() {}; };   class D2: public Base { public:     void function2() {}; };

CPS235:Polymorphism 43

Page 44: Computer Science Department Inheritance & Polymorphism

Computer Science Department

CPS235:Polymorphism 44


Top Related