C++ Classes – Polymorphism (Pt.1)
C. Papachristos
Robotic Workers Lab
University of Nevada, Reno
CS-202
Course , Projects , Labs:
Your 5th Project Deadline is this Wednesday 3/4.
Monday | Tuesday | Wednesday | Thursday | Friday | | Sunday |
|
|
| Lab (8 Sections) |
| | |
| CLASS | PASS Session | CLASS |
| | |
PASS Session | | Project DEADLINE | NEW Project | PASS Session | | PASS Session |
Course Week
CS-202 C. Papachristos
Today’s Topics
CS-202 C. Papachristos
Polymorphism Concepts & Practice
Polymorphism in Inheritance
virtual Class Methods
Late Binding
Polymorphism (prelude)
CS-202 C. Papachristos
Polymorphism & Inheritance
Polymorphism means “the ability to take many forms”.
Pointers of Base Class-type:
BigRig |
… |
Vehicle |
… |
Car |
… |
Plane |
… |
etc… |
… |
SUV |
… |
Sedan |
… |
Van |
… |
Jeep |
… |
Polymorphism (prelude)
CS-202 C. Papachristos
Polymorphism & Inheritance
Base Class-type Pointers :
SUV suv1;
Sedan sedan1, sedan2;
Jeep jeep1;
Car * suv1_Pt = &suv1;
Car * sedan1_Pt = &sedan1, * sedan2_Pt = &sedan2;
Car * jeep1_Pt = &jeep1;
This is valid: A Derived Class (SUV, Sedan, Van, Jeep) “is a type of” Base Class (Car).
A Derived Class Pointer cannot point to a Base Class Object.
Polymorphism
CS-202 C. Papachristos
Polymorphism & Inheritance
Supported through Pointers of Base Class-type:
SUV |
… |
Sedan |
… |
Van |
… |
Jeep |
… |
Derived
Class(es)
Base Class
Car |
… |
0 1 2 … 98 99
suv1
suv2
sedan1
sedan85
van56
All are
Cars
Polymorphism
CS-202 C. Papachristos
Polymorphism & Inheritance
Supported through Pointers of Base Class-type:
? Multiple arrays, one for each Child Class type.
? Combine all Child Classes into one giant Class with redundant useless info for every kind of car.
Accomplished with a single array of Base Class Pointers !
Note:
(not array of Objects because different Derived Classes require different allocation, and arrays don’t do that).
Polymorphism
CS-202 C. Papachristos
Polymorphism & Inheritance
Base Class-type Pointers :
SUV suv1;
Sedan sedan1, sedan2;
Jeep jeep1;
Car * suv1_Pt = &suv1;
Car * sedan1_Pt = &sedan1, * sedan2_Pt = &sedan2;
Car * jeep1_Pt = &jeep1;
Car *cars_Pt_arr[4];
cars_Pt_arr[0] = suv1_Pt;
cars_Pt_arr[1] = sedan1_Pt;
cars_Pt_arr[2] = sedan2_Pt;
cars_Pt_arr[3] = jeep1_Pt;
Note:
Polymorphism
CS-202 C. Papachristos
Polymorphism & Methods
Refers to the ability to associate many meanings to one function name,
Associating many meanings to one function:
Polymorphism
CS-202 C. Papachristos
Virtual
Property that indicates something that is not concretely defined.
virtual Function
Polymorphism
CS-202 C. Papachristos
Virtual
What is the purpose?
Power of Programming Abstraction:
but
Polymorphism
CS-202 C. Papachristos
Virtual
By-Example:
Classes for several kinds of GeometricFigures:
Each figure is an Object of different Class:
class Rectangle data: center point , height , width.
class Circle data: center point , radius.
All Derived from one Parent Class:
Rectangle |
m_height |
m_width |
… |
Circle |
m_radius |
… |
Inherited
GeometricFigure |
m_center |
… |
Polymorphism
CS-202 C. Papachristos
Virtual
By-Example:
Classes for several kinds of GeometricFigures:
Each figure is an Object of different Class:
class Rectangle data: height, width, center point.
class Circle data: center point, radius.
All Require a function: redraw()
Rectangle |
m_height |
m_width |
… |
Circle |
m_radius |
… |
redraw()
redraw()
?
?
GeometricFigure |
m_center |
… |
m_center
m_width
m_height
m_center
m_radius
Polymorphism
CS-202 C. Papachristos
Virtual
By-Example:
Each class needs different drawing function.
�Rectangle r;�Circle c;
�r.redraw(); //Calls Rectangle class’s redraw()�c.redraw(); //Calls Circle class’s redraw()
Nothing new here (yet).
Rectangle |
redraw() |
m_height |
m_width |
… |
Circle |
redraw() |
m_radius |
… |
GeometricFigure |
m_center |
… |
Polymorphism
CS-202 C. Papachristos
Virtual
By-Example:
Parent Class GeometricFigure contains functions�that apply to “all” figure types:
�center(): moves a figure to center of screen.
So GeometricFigure::center() would:
GeometricFigure::center() {
m_center.x = CENTER_X;
m_center.y = CENTER_Y;
redraw();
}
Rectangle |
redraw() |
m_height |
m_width |
… |
Circle |
redraw() |
m_radius |
… |
GeometricFigure |
m_center |
redraw() |
center() |
… |
Polymorphism
CS-202 C. Papachristos
Virtual
By-Example:
Parent Class GeometricFigure contains functions�that apply to “all” figure types:
�center(): moves a figure to center of screen.
So GeometricFigure::center() would:
Complications:
Rectangle |
redraw() |
m_height |
m_width |
… |
Circle |
redraw() |
m_radius |
… |
redraw()
redraw()
?
?
GeometricFigure |
m_center |
redraw() |
center() |
… |
Polymorphism
CS-202 C. Papachristos
Virtual
By-Example:
Consider a new kind of figure comes later into play:�class Triangle: Derived from GeometricFigure.
Function center() is Inherited.
It uses redraw(), which is different for each figure!
redraw()
Rectangle |
redraw() |
… |
Circle |
redraw() |
… |
Triangle |
redraw() |
… |
GeometricFigure |
m_center |
redraw() |
center() |
… |
?
Polymorphism
CS-202 C. Papachristos
Virtual
By-Example:
Consider a new kind of figure comes later into play:�class Triangle: Derived from GeometricFigure.
It will use GeometricFigure::redraw() :
Want Inherited function center() to use
function Triangle::redraw().
But Class Triangle wasn’t even written when�GeometricFigure::center() was.
Rectangle |
redraw() |
… |
Circle |
redraw() |
… |
Triangle |
redraw() |
… |
GeometricFigure |
m_center |
redraw() |
center() |
… |
redraw()
?
Polymorphism
CS-202 C. Papachristos
Virtual
How? virtual class methods give the answer.
Declaring a member function as virtual tells the C++ compiler:
Called “Late Binding” or “Dynamic Binding”.
Polymorphism
CS-202 C. Papachristos
class GeometricFigure {
public:
void redraw(){ cout<<"Not much"<<endl; }
void center(){
m_center.x = CENTER_X;
m_center.y = CENTER_Y;
redraw();
}
protected:
Point m_center;
};
class Rectangle : public GeometricFigure {
public:
void redraw(){
//Uses special members m_width , m_height
}
private:
double m_width;
double m_height;
};
Rectangle |
redraw() |
m_height |
m_width |
… |
Circle |
redraw() |
m_radius |
… |
redraw()
redraw()
?
?
GeometricFigure |
m_center |
redraw() |
center() |
… |
Usual:
“Static Binding”
Polymorphism
CS-202 C. Papachristos
class GeometricFigure {
public:
virtual void redraw(){ cout<<“Not much"<<endl; }
void center(){
m_center.x = CENTER_X;
m_center.y = CENTER_Y;
redraw();
}
protected:
Point m_center;
};
class Rectangle : public GeometricFigure {
public:
virtual void redraw(){
//Uses special members m_width , m_height
}
private:
double m_width;
double m_height;
};
Rectangle |
redraw() |
m_height |
m_width |
… |
Circle |
redraw() |
m_radius |
… |
redraw()
Polymorphic:
“Dynamic Binding”
redraw()
GeometricFigure |
m_center |
redraw() |
center() |
… |
Polymorphism
CS-202 C. Papachristos
Rectangle |
redraw() |
m_height |
m_width |
… |
Circle |
redraw() |
m_radius |
… |
redraw()
Polymorphic:
“Dynamic Binding”
redraw()
GeometricFigure |
m_center |
redraw() |
center() |
… |
Virtual – via Base class Pointers
By-Example:
gf_p = &gf;
gf_p->center() ;
gf_p->center() ;
gf_p->center() ;
(1)
(2)
(3)
m_center.x = CENTER_X;
m_center.y = CENTER_Y;
redraw();
m_center.x = CENTER_X;
m_center.y = CENTER_Y;
redraw();
m_center.x = CENTER_X;
m_center.y = CENTER_Y;
redraw();
Common Inherited Behavior (coming from Base class)
GeometricFigure * gf_p;
GeometricFigure gf;
Rectangle rect;
Circle circ;
gf_p = ▭
gf_p = ˆ
Polymorphism
CS-202 C. Papachristos
Rectangle |
redraw() |
m_height |
m_width |
… |
Circle |
redraw() |
m_radius |
… |
redraw()
Polymorphic:
“Dynamic Binding”
redraw()
GeometricFigure |
m_center |
redraw() |
center() |
… |
Virtual – via Base class Pointers
By-Example:
gf_p = &gf;
gf_p->center() ;
gf_p->center() ;
gf_p->center() ;
(1)
(2)
(3)
Ends up calling “appropriate” Method Override Dynamically
(1)
(2)
(3)
m_center.x = CENTER_X;
m_center.y = CENTER_Y;
redraw();
m_center.x = CENTER_X;
m_center.y = CENTER_Y;
redraw();
m_center.x = CENTER_X;
m_center.y = CENTER_Y;
redraw();
gf_p = ▭
gf_p = ˆ
GeometricFigure * gf_p;
GeometricFigure gf;
Rectangle rect;
Circle circ;
Polymorphism
CS-202 C. Papachristos
Rectangle |
redraw() |
m_height |
m_width |
… |
Circle |
redraw() |
m_radius |
… |
redraw()
Polymorphic:
“Dynamic Binding”
redraw()
GeometricFigure |
m_center |
redraw() |
center() |
… |
Virtual – via Base class Pointers
By-Example:
gf_p = &gf;
gf_p->center() ;
gf_p->center() ;
gf_p->center() ;
(1)
(2)
(3)
Ends up calling “appropriate” Method Override Dynamically
(1)
(2)
(3)
m_center.x = CENTER_X;
m_center.y = CENTER_Y;
redraw();
m_center.x = CENTER_X;
m_center.y = CENTER_Y;
redraw();
m_center.x = CENTER_X;
m_center.y = CENTER_Y;
redraw();
gf_p = ▭
gf_p = ˆ
Remember�These are in fact equivalent to:�this->redraw();
GeometricFigure * gf_p;
GeometricFigure gf;
Rectangle rect;
Circle circ;
Polymorphism
CS-202 C. Papachristos
Rectangle |
redraw() |
m_height |
m_width |
… |
Circle |
redraw() |
m_radius |
… |
redraw()
Polymorphic:
“Dynamic Binding”
redraw()
GeometricFigure |
m_center |
redraw() |
center() |
… |
Virtual – via Base class References
By-Example:
gf_r.center();
gr_r.center();
gc_r.center();
(1)
(2)
(3)
Ends up calling “appropriate” Method Override Dynamically
(1)
(2)
(3)
m_center.x = CENTER_X;
m_center.y = CENTER_Y;
redraw();
m_center.x = CENTER_X;
m_center.y = CENTER_Y;
redraw();
m_center.x = CENTER_X;
m_center.y = CENTER_Y;
redraw();
GeometricFigure gf; GeometricFigure & gf_r = gf;
Rectangle rect; GeometricFigure & gr_r = rect;
Circle circ; GeometricFigure & gc_r = circ;
Polymorphism
CS-202 C. Papachristos
Rectangle |
redraw() |
m_height |
m_width |
… |
Circle |
redraw() |
m_radius |
… |
redraw()
redraw()
GeometricFigure |
m_center |
redraw() |
center() |
… |
Virtual
By-Example:
GeometricFigure gf;
Rectangle rect;
Circle circ;
gf.center() ;
rect.center() ;
circ.center() ;
(1)
(2)
(3)
Object-based call means everything is known at compile-time
(1)
(2)
(3)
m_center.x = CENTER_X;
m_center.y = CENTER_Y;
redraw();
m_center.x = CENTER_X;
m_center.y = CENTER_Y;
redraw();
m_center.x = CENTER_X;
m_center.y = CENTER_Y;
redraw();
Usual:
“Static Binding”
Polymorphism
CS-202 C. Papachristos
Virtual
Another Example (a larger application problem):
Record-keeping program module for automotive parts store:
Issue:
Initially just working with regular retail sales,
but later on, discount sales, mail-order sales, etc. might come along.
These might additionally depend on other factors besides just price, tax.
Polymorphism
CS-202 C. Papachristos
Virtual
Another Example (a larger application problem):
Program must:
All will come from individual bills.
Function for computing a bill will be virtual !
Polymorphism
CS-202 C. Papachristos
Keyword virtual
Another Example (a larger application problem):
class Sale {� public:� Sale();� Sale(double price);� double getPrice() const;
� virtual double bill() const;
� double savings(const Sale&
other) const;� private:� double m_price;�};
A general Super-class:
A virtual Member Function:
Polymorphism
CS-202 C. Papachristos
Keyword virtual
Another Example (a larger application problem):
double Sale::savings(const Sale & other) const�{� return (bill() – other.bill());�}
bool operator<(const Sale & first,� const Sale & second)�{� return (first.bill() < second.bill());�}
A Member Function of Super-Class Sale.
A non-Member Function – Operator ( < ).
Both use the virtual Member Function bill().
Polymorphism
CS-202 C. Papachristos
Keyword virtual
Another Example (a larger application problem):
class DiscountSale : public Sale {� public:� DiscountSale();� DiscountSale(double price,� double discount);� double getDiscount() const;� void setDiscount(double newDisc);
� virtual double bill() const;
� private:� double m_discount;�};
The Derived Sub-class:
The Base class’ virtual Function:
Polymorphism
CS-202 C. Papachristos
Keyword virtual
Another Example (a larger application problem):
double DiscountSale::bill() const�{� double fraction = m_discount/100;� return (1 – fraction)*getPrice();�}
DiscountSale’s Member Function bill() implemented differently than Sale’s:
this definition of bill() for all Objects of DiscountSale Class
(instead of defaulting to version defined in Sales).
Derived Class’ more particular implementation of the virtual Member Function.
virtual qualifier does not appear in implementation (only declaration).
Polymorphism
CS-202 C. Papachristos
Virtual
Remember:
Yet consider the call:�DiscountSale d1, d2;�d1.savings(d2);
The call inside savings() to function bill() has no problem to work with the definition of bill() from a DiscountSale Class.
Polymorphism
CS-202 C. Papachristos
Virtual
Remember:
Even non-Member Functions can be Polymorphic.
Can pass a Pointer or a Reference to a Base Class Object.
Polymorphism
CS-202 C. Papachristos
Static vs Dynamic Binding
What is the difference with Method Overriding as known to us by now?
Static Binding (overriding as of yet)
Compiler –at “compile-time”– determines binding.
Dynamic Binding (overriding with keyword virtual)
System –at “run-time”– determines binding.
Polymorphism
CS-202 C. Papachristos
virtual Function(s) & Covariant return Type(s)
Overriding virtual Class Functions does not allow to change return Type.
“whenever the Base Class Method can be called, it should also be directly replaceable by call to Derived Class Method with no change to calling code (i.e. implicit casting is not allowed).”
class BaseClass{
public:
virtual int intFxn();
…
};
class DerivedClass : public BaseClass{
public:
virtual double intFxn();
…
};
Note: Not a case of different signatures due to conflicting return types,
it is C++ standard-enforced requirement for Dynamic Binding.
(i.e. virtual Functions)
!
Polymorphism
CS-202 C. Papachristos
virtual Function(s) & Covariant return Type(s)
Overriding virtual Class Functions does allow to have different “Covariant” return Type(s).
class BaseClass{
public:
virtual BaseClass * covarFxn();
…
};
class DerivedClass : public BaseClass{
public:
virtual DerivedClass * covarFxn();
…
};
Note: Covariant return types (Pointers!) allowed
in the context of Dynamic Binding.
(i.e. virtual Functions)
Polymorphism
CS-202 C. Papachristos
Remember: Static vs Dynamic Binding
Static Binding
class Animal {
public:
void eat(){
cout<<"Food"<<endl;
}
};
class Lion : public Animal{
public:
void eat(){
cout<<"Meat"<<endl;
}
};
int main(){
Animal animal;
Lion lion;
animal.eat(); // Food
lion.eat(); // Meat
Animal * animal_Pt = &animal;
animal_Pt->eat(); //Food
Animal * animalLion_Pt = &lion;
animalLion_Pt->eat(); //Food
return 0;
}
Objects
Object
Pointers
Static Binding
Polymorphism
CS-202 C. Papachristos
Remember: Static vs Dynamic Binding
Dynamic Binding
class Animal {
public:
virtual void eat();
};
void Animal::eat(){
cout<<"Food"<<endl;
}
class Lion : public Animal{
public:
virtual void eat();
};
void Lion::eat(){
cout<<"Meat"<<endl;
}
int main(){
Animal animal;
Lion lion;
animal.eat(); // Food
lion.eat(); // Meat
Animal * animal_Pt = &animal;
animal_Pt->eat(); //Food
Animal * animalLion_Pt = &lion;
animalLion_Pt->eat(); //Meat
return 0;
}
Objects
Object
Pointers
Dynamic Binding
Polymorphism
CS-202 C. Papachristos
Virtual
Consider:
In C++ programs, nothing happens by “magic”.
Tell C++ compiler to wait until function is used in program, and decide which definition to use based on the current calling Object.
Disadvantages:
If virtual functions are not necessary, they should be avoided.
Time for Questions !
CS-202
CS-202 C. Papachristos