polymorphism, virtual methods and abstract classes

39
Polymorphism, Virtual Methods and Abstract Classes

Upload: ulric

Post on 23-Feb-2016

49 views

Category:

Documents


0 download

DESCRIPTION

Polymorphism, Virtual Methods and Abstract Classes. Topics. Polymorphic Variables Collections of Object Pointers Virtual Functions Pure Virtual Functions Abstract Classes V-Tables Writing a ToString Function. Objectives. At the completion of this module, students should be able to:. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Polymorphism, Virtual Methods and Abstract Classes

Polymorphism, Virtual Methods

and Abstract Classes

Page 2: Polymorphism, Virtual Methods and Abstract Classes

TopicsPolymorphic VariablesCollections of Object PointersVirtual FunctionsPure Virtual FunctionsAbstract ClassesV-TablesWriting a ToString Function

Page 3: Polymorphism, Virtual Methods and Abstract Classes

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

Design classes that enable polymorphism* Properly use inheritance* Include virtual functions* Use pure virtual functions and abstract classesCorrectly use polymorphism in a program* Store addresses of dynamically created objects in arrays or vectors of base class pointersWrite and use a ToString function

Page 4: Polymorphism, Virtual Methods and Abstract Classes

Polymorphic Variables

Consider the statement:

Creature* cr1;

The declared type of the pointer cr1 is Creature

However, cr1 can potentially hold the address of anobject of a different type. In particular, it can hold the address of an object of any class derived from Creature.

Page 5: Polymorphism, Virtual Methods and Abstract Classes

Pointers to Objects

Programs that deal with lots of objects often use arrays ofpointers to those objects. Recall that a pointer is a C++ data type that stores an address. For example,

Creature* c1;

Declares c1 to be a variable that contains the address of a creature object.

Page 6: Polymorphism, Virtual Methods and Abstract Classes

Dynamic Allocation

Programs that deal with lots of objects often allocate thespace for those objects dynamically. Remember that dynamically allocated objects are stored on the heap and we use the new keyword to allocate an object dynamically:

Creature* c1 = new Creature(‘joe”, 123);

Page 7: Polymorphism, Virtual Methods and Abstract Classes

Arrays and Vectors of Object Pointers

Programs that deal with lots of objects, where the numberof objects the program has to deal with is unknown at compile time, will use an array or more often a vector to store pointers to dynamically allocated objects.

vector<Creature*> aTeam; . . . aTeam.push_back( new Creature(‘joe”, 123) );

Page 8: Polymorphism, Virtual Methods and Abstract Classes

Inheritance and Pointers

Because of the is-a relationship, an object of a derivedclass can always be treated as an object of thecorresponding base class.

In particular, you can always store the address of aderived class object in a base class pointer.

Page 9: Polymorphism, Virtual Methods and Abstract Classes

Creature* c1 = new Dwarf(“Egrew”, 600, 500, 2);

The Dwarf object

c1

c1 is aCreature pointer

Page 10: Polymorphism, Virtual Methods and Abstract Classes

So I could define a vector of Creature objects like this:

const int TEAM = 3;Vector<Creature*> aTeam;

aTeam.push_back( new Dwarf(“Bulgar”, 100, 300, 4) );aTeam.push_back( new Elf(“Razel”, 200, 200, 12) );aTeam.push_back( new Fairy(“Fiona”, 250, 150, 6, 3) );

Page 11: Polymorphism, Virtual Methods and Abstract Classes

Now what if I wrote a loop to compute the fight pointsfor each of the creatures on my team:

const int TEAM = 3;Vector<Creature*> aTeam;

aTeam.push_back( new Dwarf(“Bulgar”, 100, 300, 4) );aTeam.push_back( new Elf(“Razel”, 200, 200, 12) );aTeam.push_back( new Fairy(“Fiona”, 250, 150, 6, 3) );

for (int i = 0; i < TEAM; i++){ cout << “Fight Points = ” << aTeam[ i ]->getFightPoints( ));}

Remember that getFightPoints( ) is implemented differently in each class

Page 12: Polymorphism, Virtual Methods and Abstract Classes

Since aTeam is an array of Creature classpointers, we know that this code willcall the getFightPoints( ) method in the Creature class. Can we write this code sothat it will call the correct getFightPointsmethod for the type of object beingpointed to?

The answer is YES!

Page 13: Polymorphism, Virtual Methods and Abstract Classes

Creaturenamestrengthhitpoints

Dwarf

Virtual Functions

virtual int Creature::getFightPoints( ){ return strength;}

int Dwarf::getFightPoints( ){ return strength + weapons;}

* Make the getFightPoints function in the Creature class virtual.

Page 14: Polymorphism, Virtual Methods and Abstract Classes

const int TEAM = 3;Vector<Creature*> aTeam;

aTeam.push_back( new Dwarf(“Bulgar”, 100, 300, 4) );aTeam.push_back( new Elf(“Razel”, 200, 200, 12) );aTeam.push_back( new Fairy(“Fiona”, 250, 150, 6, 3) );

for (int i = 0; i < TEAM; i++){ cout << “Fight Points = ” << aTeam[ i ]->getFightPoints( ));}

When i = 0 invokeThe Dwarf’s getFightPoints( )function

When i = 1 invokeThe Elf’s getFightPoints( )function

When i = 2 invokeThe Fairy’sgetFightPoints( ) function

Page 15: Polymorphism, Virtual Methods and Abstract Classes

Virtual Functionsthe keyword virtual in a base class functionsays that this function will use polymorphism.When we use a base class pointer to point to the object, and invoke the virtual function, the system will automatically find and execute the function defined in the correct derived class, not the one defined in the base class!

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

This is called late binding,or dynamic binding.

virtual int Creature::GetDamage( ){ return strength;}

Page 16: Polymorphism, Virtual Methods and Abstract Classes

Rules for Polymorphism

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

In any 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.

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 a derived class object.

Page 17: Polymorphism, Virtual Methods and Abstract Classes

Virtual Tables (V-Tables)how polymorphism works

Page 18: Polymorphism, Virtual Methods and Abstract Classes

For this discussion, assume that ourCreature class has these functions:

class Creature{ … public: int getStrength( ); virtual void getFightPoints( ); virtual void toString ( );};

Page 19: Polymorphism, Virtual Methods and Abstract Classes

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

class Creature{ … public: int getStrength( ); virtual int getFightPoints( ); virtual string toString ( );};

Creature’s v-tablegetFightPoints ( ) Creature::getFightPoints( )

toString( ) Creature::toString( )

getStrength( ) is not in theV-table because it is notvirtual.

Page 20: Polymorphism, Virtual Methods and Abstract Classes

V-Tables

class Dwarf : public Creature{ … public: int getFightPoints( ); string toString(int);}

When the compiler encounters a derived class definitionthat inherits from this base class, it makes a copy of thev-table from the base class for the derived class.

Dwarf’s v-tablegetFightPoints ( ) Creature::getFightPoints( )

toString( ) Creature::toString( )

Page 21: Polymorphism, Virtual Methods and Abstract Classes

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

the signature of the toString( ) methoddoes not match the one in the base classso no change is made to the v-table in this case.

class Dwarf : public Creature{ … public: int getFightPoints( ); string toString(int);}

Dwarf’s v-tablegetFightPoints ( ) Dwarf::getFightPoints( )

toString( ) Creature::toString( )

Page 22: Polymorphism, Virtual Methods and Abstract Classes

Creature* cr1 = new Dwarf(“Dargon”, 200);

memberdata

The Dwarf object

Now … create an object and save the address of the object in a variable that is a base class pointer.

cr1

Page 23: Polymorphism, Virtual Methods and Abstract Classes

When the object of the derived class is created apointer to the class’s v-table is added to the object.

Creature* cr1 = new Dwarf(“Dargon”, 200);

memberdata

The Dwarf object

cr1

Dwarf’s v-tablegetFightPoints ( ) Dwarf::getFightPoints( )

toString( ) Creature::toString( )

Page 24: Polymorphism, Virtual Methods and Abstract Classes

When the getFightPoints( ) method is invoked …

cr1->getFightPoints ( );1. the pointer cr1 is used to find the object.

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

3. This pointer is used to locate the v-table

4. the getFightPoints function is located in the v-table and the corresponding address is used to invoke the correct method..member

data

The Dwarf object

cr1

Dwarf’s v-tablegetFightPoints ( ) Dwarf::getFightPoints( )

toString( ) Creature::toString( )

Page 25: Polymorphism, Virtual Methods and Abstract Classes

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

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

You can’t do it unless you actually know thatyou have a Dwarf object – then you could cast thePointer to a Dwarf pointer. You can test an objectusing run time type identification (RTTI)

class Dwarf : public Creature{ … public: int getFightPoints( ); string toString(int);}

Dwarf’s v-tablegetFightPoints ( ) Dwarf::getFightPoints( )

toString( ) Creature::toString( )

Page 26: Polymorphism, Virtual Methods and Abstract Classes

Downcasting an Object

Given the codeCreature* cr1 = new Dwarf(“Samuel”, 150);

You can’t invoke the toString(int) method directly,because cr1 is a Creature pointer and toString(int)is not a virtual method in the Creature class.

cr1->toString(3);

Page 27: Polymorphism, Virtual Methods and Abstract Classes

Using Run Time Type Identification

A dynamic cast verifies that a pointer can besafely converted to a pointer of a derived class.

Dwarf* dptr = dynamic_cast<Dwarf*>(aTeam[0]);

Page 28: Polymorphism, Virtual Methods and Abstract Classes

If the dynamic cast is successful, the dynamic_castoperator returns the pointer, converted to the specifiedtype. If the conversion cannot be done, a null pointer isreturned.

if (dptr ) // its not a null pointer cout << '\n' << dptr->toString( 5 );}

Dwarf* dptr = dynamic_cast<Dwarf*>(aTeam[0]);

Page 29: Polymorphism, Virtual Methods and Abstract Classes

Pure Virtual Functions

In the previous example, we over-rode the getFightPoints( )function in all of the classes derived from the Creature class. However, there was nothing in the structure of the code that forced us to do this.

To force a derived class to override a virtual function inthe base class, we must define that function as a purevirtual function.

Page 30: Polymorphism, Virtual Methods and Abstract Classes

The = 0 at the end of the functionprototype tells the compiler thatthis is a pure virtual function.

Pure virtual functions have noimplementation code in the class.

This forces every child class toimplement the function.

int getFightPoints( ) = 0;

Page 31: Polymorphism, Virtual Methods and Abstract Classes

Abstract ClassesIf a class contains at least one pure virtual function, the class becomes an abstract class.

You cannot create an object from an abstract class.

Abstract classes are truly an abstraction. They providea contract for all derived classes, defining the public methods that a derived class must implement.

If you can create an object from a class, we call thatclass a concrete class.

Page 32: Polymorphism, Virtual Methods and Abstract Classes

Abstract Classes

If a class is abstract then it is impossible to create an object of that class.

Why?

Page 33: Polymorphism, Virtual Methods and Abstract Classes

A very useful method to write for a classis the ToString Method. Most often we want the ToString method to return a textual representation of the class.

The following slides illustrate how to writethe toString method in the Creature classes.

toString( )

Page 34: Polymorphism, Virtual Methods and Abstract Classes

The ostringstream class

One of the important stream classes in C++ is thestringstream class. It operates much like the otherstream classes in C++, but instead of generating anyoutput, the ostringstream class generates a formattedstring in memory.

To retrieve the string, use the str( ) function thatbelongs to the ostingstream class.

To use the stringstream class, #include <sstream>

Page 35: Polymorphism, Virtual Methods and Abstract Classes

The toString( ) function in the Creature class:

string Creature::toString( ){ ostringstream out;

out << "My name is " << name << " .\n

out << I have " << strength << " strength points";

return out.str( );}

Notice how the stream insertion operatorworks here just like it does with an I/O stream.

create an ostringstream object

get the string from the object

Page 36: Polymorphism, Virtual Methods and Abstract Classes

The toString( ) function in the Dwarf class:

string Dwarf::toString( ){ ostringstream oss;

oss << Creature::toString( );

oss << ", " << weapons << " weapons, and “;

oss << getFightPoints( ) << " fight points.";

return oss.str( );}

create the object

call the base class toString function

add Dwarf unique stuff

Page 37: Polymorphism, Virtual Methods and Abstract Classes

Upcasting vs. DowncastingCasting from a descendant type to an ancestor type is known as upcasting. It is always safe, since you aremoving up the inheritance hierarchy. In our case, forexample, we are always know that a dwarf is a creature.

Casting from an ancestor type to a descendant typeis called downcasting. In our case, we can’t guaranteethat every creature is a dwarf, so downcasting a creature to a dwarf can be very dangerous, sincewe assume that information may be there that isn’t.

Page 38: Polymorphism, Virtual Methods and Abstract Classes

You can store the reference to a base class objectin a derived class reference, but you must do anexplicit cast to make this work.

Dwarf* dw1;Creature* c1 = new Creature(“joe”, 400);

Dw1 = (Dwarf)c1;

Page 39: Polymorphism, Virtual Methods and Abstract Classes

This is pretty dangerous and not often used, becausethe derived class reference thinks it is referencing aderived class object, but it really isn’t. This isreferred to as the “slicing problem”.

A Creature object

dw1

basepart

there is no derived part.If you try to access memberdata in the derived part, youwill get garbage!