starting out with c++ early objects seventh edition

41
Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-Wesley Starting Out with C++ Early Objects Seventh Edition by Tony Gaddis, Judy Walters, and Godfrey Muganda Chapter 15: Polymorphism and Virtual Functions

Upload: henry-noel

Post on 31-Dec-2015

25 views

Category:

Documents


1 download

DESCRIPTION

Chapter 15: Polymorphism and Virtual Functions. Starting Out with C++ Early Objects Seventh Edition by Tony Gaddis, Judy Walters, and Godfrey Muganda. Animal. Cat. Dog. Poodle. 15.1 Type Compatibility in Inheritance Hierarchies. Classes in a program may be part of an - PowerPoint PPT Presentation

TRANSCRIPT

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-Wesley

Starting Out with C++ Early Objects Seventh Edition

by Tony Gaddis, Judy Walters, and Godfrey Muganda

Chapter 15: Polymorphism and Virtual Functions

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-Wesley

15.1 Type Compatibility in Inheritance Hierarchies

• Classes in a program

may be part of an

inheritance hierarchy

• Classes lower in the

hierarchy are special

cases of those above

15-2

Animal

Cat Dog

Poodle

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-Wesley

Type Compatibility in Inheritance

• A pointer to a derived class can be assigned to a pointer to a base class. Another way to say this is:

• A base class pointer can point to derived class objects

Animal *pA = new Cat;

15-3

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-Wesley

Type Compatibility in Inheritance

• Assigning a base class pointer to a derived class pointer requires a cast

Animal *pA = new Cat; Cat *pC; pC = static_cast<Cat *>(pA);• The base class pointer must already

point to a derived class object for this to work

15-4

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-Wesley

Using Type Casts with Base Class Pointers• C++ uses the declared type of a pointer to

determine access to the members of the pointed-to object

• If an object of a derived class is pointed to by a base class pointer, all members of the derived class may not be accessible

• Type cast the base class pointer to the derived class (via static_cast) in order to access members that are specific to the derived class

• See project BasePointerCasting

15-5

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-Wesley

15.2 Polymorphism and Virtual Member Functions

• Polymorphic code: Code that behaves differently when it acts on objects of different types

• Virtual Member Function: The C++ mechanism for achieving polymorphism

15-6

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-Wesley

Polymorphism

Consider the Animal, Cat, Dog hierarchy where each class has its own version of the member function id( )

15-7

Animal

Cat Dog

Poodle

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-Wesley

Polymorphism

class Animal{ public: void id(){cout << "animal";}

}

class Cat : public Animal{ public: void id(){cout << "cat";}

}

class Dog : public Animal{ public: void id(){cout << "dog";}

}

15-8

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-Wesley

Polymorphism• Consider the collection of different Animal objects Animal *pA[] = {new Animal, new Dog, new Cat}; and accompanying code for(int k=0; k<3; k++) pA[k]->id();

• Prints: animal animal animal, ignoring the more specific versions of id() in Dog and Cat

• See project NonPolymorphic

15-9

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-Wesley

Polymorphism

• Preceding code is not polymorphic: it behaves the same way even though Animal, Dog and Cat have different types and different id() member functions

• Polymorphic code would have printed "animal dog cat" instead of "animal animal animal"

15-10

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-Wesley

Polymorphism

• The code is not polymorphic because in the expression

pA[k]->id() the compiler sees only the type of the

pointer pA[k], which is pointer to Animal• Compiler does not see type of actual object

pointed to, which may be Animal, or Dog, or Cat

15-11

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-WesleyInheritance &

Polymorphism12

Class Hierarchies• PassFailActivity inherits score from

GradedActivity and has its own member variable minPassingScore

• PassFailExam inherits score and minPassingScore from PassFailActivity and has its own member variables numQuestions, pointsEach,numMissed

• PassFailActivity redefines function getLetterGrade so that the the letter grade is either P or F and not A,B,C or D as computed by getLetterGrade in GradedActivity

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-WesleyInheritance &

Polymorphism13

GradedActivity .h and .cpp

#ifndef GRADEDACTIVITY_H#define GRADEDACTIVITY_H

// GradedActivity class declaration

class GradedActivity{protected: double score; // To hold the numeric scorepublic: // Default constructor GradedActivity() { score = 0.0; }

// Constructor GradedActivity(double s) { score = s; }

// Mutator function void setScore(double s) { score = s; } // Accessor functions double getScore() const { return score; } char getLetterGrade() const;};#endif

#include "GradedActivity.h"

//***********************************************

//Member function GradedActivity::getLetterGrade*

//***********************************************

char GradedActivity::getLetterGrade() const

{

char letterGrade; // To hold the letter grade

if (score > 89)

letterGrade = 'A';

else if (score > 79)

letterGrade = 'B';

else if (score > 69)

letterGrade = 'C';

else if (score > 59)

letterGrade = 'D';

else

letterGrade = 'F';

return letterGrade;

}

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-WesleyInheritance &

Polymorphism14

FinalExam .h and .cpp

#ifndef FINALEXAM_H#define FINALEXAM_H#include "GradedActivity.h"

class FinalExam : public GradedActivity{private: int numQuestions; // Number of questions double pointsEach; // Points for each question int numMissed; // Number of questions missedpublic: FinalExam() { numQuestions = 0; pointsEach = 0.0; numMissed = 0; } FinalExam(int questions, int missed) { set(questions, missed); } void set(int, int); // Defined in FinalExam.cpp

double getNumQuestions() const { return numQuestions; } double getPointsEach() const { return pointsEach; } int getNumMissed() const { return numMissed; }};#endif

#include "FinalExam.h"

//********************************************************

// set function *

// The parameters are the number of questions and the *

// number of questions missed. *

//********************************************************

void FinalExam::set(int questions, int missed)

{

double numericScore; // To hold the numeric score

// Set the number of questions and number missed.

numQuestions = questions;

numMissed = missed;

// Calculate the points for each question.

pointsEach = 100.0 / numQuestions;

// Calculate the numeric score for this exam.

numericScore = 100.0 - (missed * pointsEach);

// Call the inherited setScore function to set

// the numeric score.

setScore(numericScore);

}

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-WesleyInheritance &

Polymorphism15

PassFailActivity .h and .cpp#ifndef PASSFAILACTIVITY_H#define PASSFAILACTIVITY_H#include "GradedActivity.h"

class PassFailActivity : public GradedActivity{protected: double minPassingScore; // Minimum passing score.public: // Default constructor PassFailActivity() : GradedActivity() { minPassingScore = 0.0; } // Constructor PassFailActivity(double mps) : GradedActivity() { minPassingScore = mps; }

// Mutator void setMinPassingScore(double mps) { minPassingScore = mps; }

// Accessors double getMinPassingScore() const { return minPassingScore; } char getLetterGrade() const;};#endif

#include "PassFailActivity.h"

//******************************************************

// Member function PassFailActivity::getLetterGrade *

// This function returns 'P' if the score is passing, *

// otherwise it returns 'F'. *

//******************************************************

char PassFailActivity::getLetterGrade() const

{

char letterGrade;

if (score >= minPassingScore)

letterGrade = 'P';

else

letterGrade = 'F';

return letterGrade;

}

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-WesleyInheritance &

Polymorphism16

PassFailExam .h and .cpp#ifndef PASSFAILEXAM_H#define PASSFAILEXAM_H#include "PassFailActivity.h"

class PassFailExam : public PassFailActivity{private: int numQuestions; // Number of questions double pointsEach; // Points for each question int numMissed; // Number of questions missedpublic: // Default constructor PassFailExam() : PassFailActivity() { numQuestions = 0; pointsEach = 0.0; numMissed = 0; } // Constructor PassFailExam(int questions, int missed, double mps) : PassFailActivity(mps) { set(questions, missed); }

// Mutator function void set(int, int); // Defined in PassFailExam.cpp

// Accessor functions double getNumQuestions() const { return numQuestions; } double getPointsEach() const { return pointsEach; } int getNumMissed() const { return numMissed; }};#endif

#include "PassFailExam.h"

//********************************************************

// set function *

// The parameters are the number of questions and the *

// number of questions missed. *

//********************************************************

void PassFailExam::set(int questions, int missed)

{

double numericScore; // To hold the numeric score

// Set the number of questions and number missed.

numQuestions = questions;

numMissed = missed;

// Calculate the points for each question.

pointsEach = 100.0 / numQuestions;

// Calculate the numeric score for this exam.

numericScore = 100.0 - (missed * pointsEach);

// Call the inherited setScore function to set

// the numeric score.

setScore(numericScore);

}

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-WesleyInheritance &

Polymorphism17

Consider this functionConsider this function

Because the parameter in the displayGrade function is a GradedActivity reference variable, it can reference

any object that is derived from GradedActivity. That means we can pass a GradedActivity object, a

FinalExam object, a PassFailExam object, or any other object that is derived from GradedActivity.

A problem occurs in this program however...

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-WesleyInheritance &

Polymorphism18

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-WesleyInheritance &

Polymorphism19

As you can see from the example output, the getLetterGrade

member function returned ‘C’ instead of ‘P’.

This is because the GradedActivity class’ getLetterGrade function

was executed instead of the PassFailActivity class’s version of the

function.

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-WesleyInheritance &

Polymorphism20

Static Binding• Program 15-9 displays 'C' instead of 'P'

because the call to the getLetterGrade function is statically bound (at compile time) with the GradedActivity class's version of the function.– Thus, the actual letter grade is computed instead of

the P/F grade

• We can remedy this by making the getLetterGrade function virtual in GradedActivity.

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-Wesley

Virtual Functions

• Declaring a function virtual will make the compiler check the type of each object to see if it defines a more specific version of the virtual function

• At runtime, C++ determines the type of object making the call, and binds the function to the appropriate version of the function.

15-21

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-Wesley

Virtual Functions

If the member functions id()are declared virtual, then the code

Animal *pA[] = {new Animal, new Dog,new Cat}; for(int k=0; k<3; k++) pA[k]->id();

will print animal dog cat

15-22

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-Wesley

Virtual Functions

How to declare a member function virtual:class Animal{ public: virtual void id(){cout << "animal";}}class Cat : public Animal{ public: virtual void id(){cout << "cat";}}class Dog : public Animal{ public: virtual void id(){cout << "dog";}}

15-23

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-Wesley

Function Binding

• In pA[k]->id(), Compiler must choose which version of id() to use: There are different versions in the Animal, Dog, and Cat classes

• Function binding is the process of determining which function definition to use for a particular function call

• The alternatives are static and dynamic binding

15-24

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-Wesley

Static Binding

• Static binding chooses the function in the class of the base class pointer, ignoring any versions in the class of the object actually pointed to

• Static binding is done at compile time

15-25

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-Wesley

Dynamic Binding

• Dynamic Binding determines the function to be invoked at execution time

• Can look at the actual class of the object pointed to and choose the most specific version of the function

• Dynamic binding is used to bind virtual functions• As long as the array or pointer that holds the

objects of the child classes has a virtual function, dynamic binding will occur even if the child functions are not virtual

• See project Polymorphic-Virtual15-26

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-WesleyInheritance &

Polymorphism27

Updated Version of GradedActivityUpdated Version of GradedActivity

The function

is now virtual.

The function also becomes virtual in all

derived classes automatically!

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-WesleyInheritance &

Polymorphism28

If we recompile our program with the updated versions of the

classes, we will get the right output, shown here (project

GradedActivity-3):

This type of behavior is known as polymorphism. The term

polymorphism means the ability to take many forms.

The program demonstrates polymorphism by passing

objects of the GradedActivity and PassFailExam classes to the

displayGrade function.

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-WesleyInheritance &

Polymorphism29

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-WesleyInheritance &

Polymorphism30

Virtual Destructors• It's a good idea to make destructors virtual if the class

could ever become a base class.• Otherwise, the compiler will perform static binding on

the destructor if the class ever is derived from.• If the derived class is pointed to by an object of the

base class, only the base class destructor will be called– Making the base class destructor virtual will enable both

destructors to execute– When a base class function is declared virtual, all overridden

versions of the function in derived classes automatically become virtual

– Including a virtual destructor in a base class, even one that does nothing, will ensure that any derived class destructors will also be virtual

– See project VirtualDestructor

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-Wesley

15.3 Abstract Base Classes and Pure Virtual Functions

• An abstract class is a class that contains no objects that are not members of subclasses (derived classes)

• For example, in real life, Animal is an abstract class: there are no animals that are not dogs, or cats, or lions…

15-31

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-Wesley

Abstract Base Classes and Pure Virtual Functions

• Abstract classes are an organizational tool: useful in organizing inheritance hierarchies

• Abstract classes can be used to specify an interface that must be implemented by all subclasses

15-32

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-Wesley

Abstract Functions

• The member functions specified in an abstract class do not have to be implemented

• The implementation is left to the subclasses

• In C++, an abstract class is a class with at least one abstract member function

15-33

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-Wesley

Pure Virtual Functions

• In C++, a member function of a class is declared to be an abstract function by making it virtual and replacing its body with = 0;

class Animal{ public: virtual void id()=0; };• A virtual function with its body omitted and

replaced with =0 is called a pure virtual function, or an abstract function

15-34

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-Wesley

Abstract Classes• An abstract class can not be instantiated• An abstract class can only be inherited

from: that is, you can derive classes from it

• Classes derived from abstract classes must override the pure virtual function with a concrete member function before they can be instantiated.

• See project AbstractBaseClass2

15-35

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-WesleyInheritance &

Polymorphism36

Abstract Base Classes and Pure Virtual Functions

• In Student.h we have a pure virtual function virtual int getRemainingHours() const = 0;

• This is defined in CsStudent.cppint CsStudent::getRemainingHours() const

{

int reqHours, // Total required hours

remainingHours; // Remaining hours

// Calculate the required hours.

reqHours = MATH_HOURS + CS_HOURS + GEN_ED_HOURS;

// Calculate the remaining hours.

remainingHours = reqHours - (mathHours + csHours + genEdHours);

// Return the remaining hours.

return remainingHours;

}

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-WesleyInheritance &

Polymorphism37

Abstract Base Classes and Pure Virtual Functions

• There is no meaning to calculating the remaining hours for a general student – each major has its own requirements

• Thus, the pure virtual function in class Student which is given specific definition each derived class

• See project AbstractBaseClass

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-WesleyInheritance &

Polymorphism38

Multiple Inheritance

• A derived class can have more than one base class

• Each base class can have its own access specification in derived class's definition:class cube : public square,

public rectSolid;

class

square

class

rectSolid

class

cube

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-WesleyInheritance &

Polymorphism39

Multiple Inheritance• Arguments can be passed to both base

classes' constructors:cube::cube(int side) : square(side),

rectSolid(side, side, side);

DateTime::DateTime(int dy, int mon, int yr, int hr, int mt, int sc) : Date(dy, mon, yr), Time(hr, mt, sc)

• The order the base class constructor calls appear in the list does not matter. They are called in order of inheritance.– Base class constructors are called in order they are

listed in the first line of the class declaration

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-WesleyInheritance &

Polymorphism40

Multiple Inheritance

• Problem: what if base classes have member variables/functions with the same name?

• Solutions:– Derived class redefines the multiply-defined function– Derived class invokes member function in a particular base

class using scope resolution operator ::

• Compiler errors occur if derived class uses base class function without one of these solutions

• See project MultipleInheritance

Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-Wesley

Starting Out with C++ Early Objects Seventh Edition

by Tony Gaddis, Judy Walters, and Godfrey Muganda

Chapter 15: Polymorphism and Virtual Functions