polymorphism and virtual functions. topics polymorphism virtual functions pure virtual functions...

41
Polymorphism and Virtual Functions

Upload: anastasia-boulter

Post on 29-Mar-2015

243 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

Polymorphism and Virtual Functions

Page 2: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

TopicsPolymorphismVirtual FunctionsPure Virtual FunctionsAbstract Base ClassesVirtual DestructorsV-TablesRun Time Type Identification (RTTI)Dynamic Cast

Page 3: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

Objectives

At the completion of this module, students should be able to:

Design classes that enable polymorphism* Properly use inheritance* Include virtual functionsCorrectly use polymorphism in a program* Store pointers to dynamically created objects in arrays of base class pointersExplain how V-Tables are used to make polymorphism workExplain why a virtual destructor is neededSafely access base class functions in a program, using rtti anddynamic casts.

Page 4: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

Introduction : The Orchestra

Page 5: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

Polymorphic Variables

Consider the statement:

Instrument* instr = new Brass(“bugle”, “toot”);

The declared or “static” type of instr is Instrument*

However, instr can potentially hold a pointer to avariable of a different type. In particular, it can hold the address of an object of any class derived from Instrument. The type of object actually pointed to is instr’s “dynamic” type.

Page 6: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

From Inheritance . . .

Recall that you can store the address of a derived classobject in a base class pointer.

What happens if you use the base class pointer toinvoke a function that exists in the base class, but hasbeen over-ridden in the derived class?

Page 7: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

Virtual Functionsclass Instrument{ public: virtual void play ( ) const; void display ( ); protected: string name;};

the keyword virtual says that wecan over-ride this function in aderived class. But, when we use a baseclass pointer to point to the object,and invoke the virtual function, thesystem will automatically find andexecute the function defined in the derived class, not the base class!

Moreover, if we have many different derivedclasses, the system will find the correctfunction for the object that the pointer points to.

This is called late binding,or dynamic binding.

Page 8: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

bugle

toot

Brass joe(“bugle”, “toot”);String mary(“harp”, “strummm”);Percussion bill(“kettle”, “whomp”);

Instrument* instr;instr = &joe;instr->play( );

instr = &mary;instr->play( );

instr = &bill;instr->play( );

harp

strumm

kettle

whomp

instr

joe

mary

bill

Page 9: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

bugle

toot

Brass joe(“bugle”, “toot”);String mary(“harp”, “strummm”);Percussion bill(“kettle”, “whomp”);

Instrument* instr;instr = &joe;instr->play( );

instr = &mary;instr->play( );

instr = &bill;instr->play( );

harp

strumm

kettle

whomp

instr

joe

mary

bill

Page 10: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

bugle

toot

Brass joe(“bugle”, “toot”);String mary(“harp”, “strummm”);Percussion bill(“kettle”, “whomp”);

Instrument* instr;instr = &joe;instr->play( );

instr = &mary;instr->play( );

instr = &bill;instr->play( );

harp

strumm

kettle

whomp

instr

joe

mary

bill

Page 11: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

Foo

Bar Widget

Page 12: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

Foo

Bar Widget

# myData : string

printMyData( ) : void

- barData1 : string

+ printMyData( ) : void

- widgetData1 : string

+ printMyData( ) : void

Page 13: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

Foo

Bar Widget

# myData : string

+ printMyData( ) : void

- barData1 : string

+ printMyData( ) : void

- widgetData1 : string

+ printMyData( ) : void

void printMydata( ){ cout << “I am a Foo object, my data is “ << myData << endl;}

Page 14: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

Foo

Bar Widget

# myData : string

+ printMyData( ) : void

- barData : string

+ printMyData( ) : void

- widgetData2 : string

+ printMyData( ) : void

void printMydata( ){ cout << “I am a Bar object, my data is “ << myData << barData << endl;}

myData is visibleto the child class

Page 15: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

Foo

Bar Widget

# myData : string

+ printMyData( ) : void

- barData : string

+ printMyData( ) : void

- widgetData : string

+ printMyData( ) : void

void printMydata( ){ cout << “I am a Widget object, my data is “ << myData << widgetData << endl;}

Page 16: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

What will the following do?

Foo foo (“C++ Rocks”);Bar bar (“Prof deBry”, “Rocks?”);Widget widget(“I Love”, “C++”);

foo.printMyData( );bar.printMyData( );widget.printMyData( );

Page 17: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

But …What will the following do?

Foo *fooPtrs[3];fooPtrs[0] = &foo;fooPtrs[1] = &bar;fooPtrs[2] = &widget;

fooPtrs[0]->printMyData( );fooPtrs[1]->printMyData( );fooPtrs[2]->printMyData( );

Page 18: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

What will the following do?

Make printMyData( ) virtual

Foo *fooPtrs[3];fooPtrs[0] = &foo;fooPtrs[1] = &bar;fooPtrs[2] = &widget;

fooPtrs[0]->printMyData( );fooPtrs[1]->printMyData( );fooPtrs[2]->.printMyData( );

Page 19: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

Try it …

Page 20: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

Rules for Polymorphism

In the base class, the keyword virtual must precedeany function that you want to call using polymorphism.

In the derived class the signature must exactly matchthe signature of the function being over-ridden. If thesignature is different, the compiler considers it to bea different function, not an over-riding function.

The actual implementation of the function in thederived class will be different than that in the baseclass.

The function is invoked through a base class pointerthat contains the address of the derived class object.

Page 21: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

Pure Virtual Functions

In the previous example, we provided an implementationfor the printMyData( ) function in the base class. Often times you will not need to provide an implementation for a virtual function in the base class.

You can do this by making the function a pure virtualfunction. Pure virtual functions have no implementation.

Page 22: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

class Foo{ public: virtual void printMyData( ) const = 0; protected: string myData;}

the =0 notation signals that thisis a pure virtual function. Thereshould be no implementation ofthis function written.

Page 23: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

Abstract Classes

If a class contains at least one pure virtual functionthen it is impossible to create an object of that class.

Why?

Such classes are called abstract classes.

Page 24: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

Virtual Destructors

If an object is destroyed by applying the delete operatorto a base class pointer, only the base class destructor iscalled. This can leave derived class data members on theheap with no way to delete them.

This problem is solved by making the destructor in thebase class virtual. Polymorphism then causes the derivedclass destructor to be called first. It will automatically callthe base class destructor, insuring that all data isproperly removed from the heap.

Page 25: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

V-TablesWhen the compiler encounters a class definitionthat contains virtual functions, it builds a v-tablefor that class. The v-table contains the addressesof all of the virtual functions for the class.

class Instrument{ public: int getValue( ); virtual void play ( ); virtual void display ( ); virtual ~Instrument ( );};

Instrument’s v-table

play ( )

~Instrument( )

Instrument::play

Instrument::~Instrument

display( ) Instrument::display

Page 26: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

When the compiler encounters a derived class definitionthat inherits publicly from this base class, it copies thev-table from the base class for the derived class.

class Brass : public Instrument{ public: void play ( ); void display ( int ); ~Brass ( );};

Brass’s v-table

play ( )

~Instrument( )

Instrument::play

Instrument::~Instrument

display( ) Instrument::display

Page 27: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

Now, for any function in the derived class that over-ridesa virtual function in the base class, the compiler sets theaddress for that function to the derived class function’saddress.

class Brass{ public:

Brass’s v-table

play ( )

~Instrument( )

Instrument::play

Instrument::~Instrument

display( ) Instrument::display

void play ( );

Brass::play( )

void display( int);

~Brass( );

Brass::~Brass( )

the signature of the display functiondoes not match the one in the base

class, so no change is made to the v-table.

Page 28: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

Brass’s v-table

play ( )

~Instrument( )

display( ) Instrument::display( )

Brass::play( )

Brass::~Brass( )

Now, when an object of the derived class is createda pointer to the class’s v-table is added to the object.

Instrument* orchestra = new Brass( … some parameters…);

memberdata

The Brass object

Page 29: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

The address of the object is saved in a base class pointer

Brass’s v-table

play ( )

~Instrument( )

display( ) Instrument::display( )

Brass::play( )

Brass::~Brass( )myTuba

memberdata

orchestra

Instrument* iPtr = new Brass( … some parameters…);

Page 30: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

Invoke the play( ) function

Brass’s v-table

play ( )

~Instrument( )

display( ) Instrument::display( )

Brass::play( )

Brass::~Brass( )myTuba

memberdata

orchestra -> play ( );

orchestra

1. the pointer is dereferenced to find the object.

2. the pointer to the v-table is located in the object.

3. This pointer is dereferenced to access the v-table

4. the play( ) function is located in the v-table and the corresponding address is used to invoke the play function.

Page 31: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

What happens now if you want to invoke thedisplay (int) function from the Brass class?

class Brass{ public: void play ( ); void display ( int ); ~Brass ( );}; Brass’s v-table

play ( )

~Instrument( )

Instrument::play

Instrument::~Instrument

display( ) Instrument::display

the function display (int) was not defined in the base class, and it is not virtual, so itis not in the v-table.

Page 32: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

So, if you write

orchestra -> display ( 5 );

You will get a compiler error, becauseOrchestra is a base class pointer, and thefunction display ( int ) is not defined in thebase class.

Page 33: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

As you have seen, when you store the addressof a derived class object in a base class pointer,you lose information about the class that theobject belongs to. Thus, it seems impossible toinvoke the derived class function display (int) withthe statement

orchestra -> display (5);

Page 34: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

We could cast the pointer to a derived classpointer … but what if we are not sure thatthe object being pointed to really is an objectof the Brass class?

Page 35: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

Run Time Type Identification

Run Time Type Identification (RTTI) provides a wayto find out what kind of an object is pointed to by abase class pointer.

To find the type of object being pointed to, we usea special function typeid ( ). To use this function wemust #include <typeinfo>.

Page 36: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

Instrument

virtual void play( )

Brass

virtual void play( )void play (int)

Percussion

virtual void play( )

Woodwind

virtual void play( )

Consider the inheritance hierarchy …

Page 37: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

And suppose you have the following situation:

Instrument *orchestra[3];

orchestra[0] = new Brass (some parameters);orchestra[1] = new Percussion (some parameters);orchestra[2] = new Woodwind (some parameters);

… and you want to execute the line

orchestra[0]->display(37);

Page 38: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

Since orchestra[0] contains a base class pointerand play(int) is not in the v-table …

orchestra[0]->play(37);

will give you a compiler error

So … how do you execute Brass class play(int) function?

Page 39: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

We can determine whether or not an object pointedto in the array of base class pointers is a Brassinstrument by writing

for (int i = 0; i < 3; i++ ){ if ((typeid (*orchestra[i])) == typeid (Brass)) { // code }} dereference the pointer

and get the typeid of whatit points to.

then compare it with thetypeid of the Brass class.

Page 40: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

If we determine that the object pointed to is, in fact,an object of the Brass class, then we can downcastthe pointer and invoke the derived class function.

In this case we use a dynamic cast. The dynamic cast checks at run time to be sure that the cast is safe.

Dynamic Casting

dynamic_cast<Brass*>(orchestra[i]) -> play (5);

this is a base class pointerthis casts the pointer

to a Brass pointerand we can now invokethe play (int) function!

Page 41: Polymorphism and Virtual Functions. Topics Polymorphism Virtual Functions Pure Virtual Functions Abstract Base Classes Virtual Destructors V-Tables Run

Notes

• There is some overhead involved with the use of RTTI• The typeid function should only be used for comparisons• Dynamic casting also involves some overhead• Dynamic casting only works with pointers