Understanding Polymorphism tMyn1 Understanding Polymorphism Polymorphism requires the use of derived classes. It always involves the use of a pointer to.
Post on 18-Jan-2016
221 Views
Preview:
Transcript
Understanding Polymorphism
tMyn 1
Understanding Polymorphism
• Polymorphism requires the use of derived classes.• It always involves the use of a pointer to an object or
a reference to an object.• Polymorphism only operates within a class hierarchy,
so the ability to derive one class from another is fundamental to making polymorphism possible.
• The first step is the need to understand the role of a pointer to a base class.
Understanding Polymorphism
tMyn 2
• The objects of a derived class represent a subset of objects of the base class – in other words, every derived class object is also a base class object.
• Consequently, you can always use a pointer to base class to store the address of a derived class object – in fact, you can even use a pointer to an indirect base class for this purpose.
• REMEMBER, however, that a problem arises, though, when you want to destroy objects through a base class pointer – and this will be addressed later on…:
Understanding Polymorphism
tMyn 3
#include "stdafx.h"#include <iostream>
using namespace System;using namespace std;
class Box{public:
Box(); ~Box();
double volume();private: double length;
double breadth; double height;
};
Understanding Polymorphism
tMyn 4
Box::Box(){ cout<<"Base class constructor, object "<<this<<endl;
cout<<"Length: "; cin>>length;
cin.get();cout<<"Breadth: ";
cin>>breadth;cin.get();cout<<"Height: ";
cin>>height;cin.get();
}Box::~Box(){ cout<<"Base class destructor, object "<<this<<endl;}
Understanding Polymorphism
tMyn 5
double Box::volume(){
return length*breadth*height;}class Carton:public Box{public: Carton(); ~Carton();private: double weight;};
Understanding Polymorphism
tMyn 6
Carton::Carton(){ cout<<"Derived class constructor, object ”
<<this<<endl;cout<<"Weight: ";
cin>>weight;cin.get();
}Carton::~Carton(){ cout<<"Derived class destructor, object ”
<<this<<endl;}
Understanding Polymorphism
tMyn 7
int main(array<System::String ^> ^args){
Carton* fourth=new Carton(); delete fourth;
Box* fifth=new Carton(); delete fifth; return 0;}
Understanding Polymorphism
tMyn 8
The derived class destructor will never be called!
Understanding Polymorphism
tMyn 9
• Even if you can use a pointer to base to store the address of a derived class object, the reverse of this is not true.
• This is logical, because the base classes do not describe a complete derived class object.
• A derived class object always contains a complete sub-object of each of its bases, but each base class only represents a part of a derived class object.
• Let’s start with an example that is not a satisfactory one. The aim of the next example is to look more closely at the behaviour of inherited member functions and the relationship that they have with derived class member functions.
Understanding Polymorphism
tMyn 10
• First we revise the Box class to include a function that calculates the volume (double calcVol()) of a Box object and another function that displays the resulting volume (void displayVol()).
• As a second step we define a different calculate volume -function in the derived class (double calcVol()).
• The idea here is that we can (??) get the inherited function displayVol() to call the derived class version of the function calcVol() when we call it for an object of the Carton class:
Understanding Polymorphism
tMyn 11
#include "stdafx.h"#include <iostream>#include <string>using namespace System;using namespace std;
class Box{public:
Box(); Box(double, double, double); ~Box(); void displayVol(); double calcVol();
protected: double length; double breadth; double height;};
Understanding Polymorphism
tMyn 12
Box::Box(){
cout<<"Base class default constr., object ” <<this<<endl;cout<<"Length: ";
cin>>length;cin.get();cout<<"Breadth: ";
cin>>breadth;cin.get();cout<<"Height: ";
cin>>height;cin.get();
}
Understanding Polymorphism
tMyn 13
Box::Box(double lv, double bv, double hv){
cout<<"Base class constructor with 3 params., object ”<<this<<endl;
length=lv; breadth=bv; height=hv;
}Box::~Box(){ cout<<"Base class destructor, object "<<this<<endl;}void Box::displayVol(){ cout<<"Usable volume is "<<calcVol()<<endl;}
Understanding Polymorphism
tMyn 14
double Box::calcVol(){
return length*breadth*height;}class Carton:public Box{public:
Carton(); Carton(string); Carton(double, double, double, string); ~Carton(); double calcVol();private: string* text;};
Understanding Polymorphism
tMyn 15
Carton::Carton():Box(){ cout<<"Derived class default constr., object ”
<<this<<endl;text=new string;cout<<"Typical usage: ";
getline(cin, *text);}Carton::Carton(string message):Box(){ cout<<"Derived class constructor with 2 params, object "
<<this<<endl; text=new string;
*text=message;}
Understanding Polymorphism
tMyn 16
Carton::Carton(double lVal, double bVal, double hVal, string message):Box(lVal, bVal, hVal){
cout<<"Derived class constructor with 4 params., object ” <<this<<endl;
text=new string; *text=message;
}Carton::~Carton(){ cout<<"Derived class destructor, object "<<this<<endl; delete text; text=0;}
Understanding Polymorphism
tMyn 17
Carton::~Carton(){
cout<<"Derived class destructor, object "<<this<<endl; delete text; text=0;}double Carton::calcVol(){ return 0.85*length*breadth*height;}int main(array<System::String ^> ^args){
Box first=Box(); first.displayVol(); Carton second=Carton(); second.displayVol(); return 0;}
Understanding Polymorphism
tMyn 18
The output is rather disappointing:
Understanding Polymorphism
tMyn 19
• The trouble is that in this program, when the calcVol() function is called by the displayVol() function, the compiler sets it once and for all as the version of calcVol() defined in the base class.
• No matter how you call displayVol(), it will never call the Carton version of the calcVol() function.
• When function calls are fixed in this way, before the program is executed, it is called static resolution of the function call or static binding.
• The term early binding is also commonly used.• A particular calcVol() function is bound to the call
from the function displayVol() during the compilation of the program.
Understanding Polymorphism
tMyn 20
• What if we call the calcVol() function for the Carton object directly?:
Understanding Polymorphism
tMyn 21
int main(array<System::String ^> ^args){
Box first=Box(); first.displayVol(); Carton second=Carton(); second.displayVol();
cout<<"New try:"<<endl <<"The volume is "<<second.calcVol()<<endl;
return 0;}
Understanding Polymorphism
tMyn 22
That worked.. and the call was resolved statically!
Understanding Polymorphism
tMyn 23
• Next try: let’s add the statement to call the calcVol()- function through a pointer to the base class:
Understanding Polymorphism
tMyn 24
int main(array<System::String ^> ^args){
Box first=Box(); first.displayVol(); Carton second=Carton(); second.displayVol();
Box* pBox=&second; cout<<"Next try: "<<endl
<<"The volume is "<<pBox->calcVol()<<endl; return 0;}
Understanding Polymorphism
tMyn 25
Did not work!
Understanding Polymorphism
tMyn 26
• As a summary:• A call to calcVol() for the derived class object,
second, calls the derived class calcVol() function, which was what we wanted.
• The call through the base class pointer pBox, however, is resolved to the base class version of calcVol(), even though pBox contains the address of the object second.
• In other words, both calls are resolved statically.• The compiler will implement these calls as:
Understanding Polymorphism
tMyn 27
cout<<"New try: "<<endl <<“The volume is “ <<second.Carton:: calcVol();
and:
cout<<“Next try: "<<endl <<“The volume is “
<<pBox->Box:: calcVol();
Understanding Polymorphism
tMyn 28
• A static call of a function through a pointer is determined solely by the type of the pointer, and not by the object to which it points.
• The pointer pBox is of type pointer to Box, so any static call using pBox can only call a function member of Box.
• In other words: any call to a function through a base class pointer that is resolved statically will call a base class function.
Understanding Polymorphism
tMyn 29
• How should the program work?• If we call displayVol() with a derived class object, we
would like it to determine that the derived class calcVol() function should be called, not the base class version.
• Similarly, if we call the calcVol() function through a base class pointer, then we want it to choose the calcVol() function that is appropriate to the object pointed to.
• This sort of operation is referred to as dynamic binding or late binding.
• In order to achieve our aims we need to specify that calcVol() is a virtual function.
Understanding Polymorphism
tMyn 30
• When you declare a function as virtual in a base class, you indicate to the compiler that you want dynamic binding for the function in any class that’s derived from this base class.
top related