1
COSC3557: Object-Oriented Programming
Haibin Zhu, Ph. D.
Assistant Professor of CS, Nipissing University
2
Lecture 6
Polymorphism and overloading
Ref. : 14.1 and Chapter 15
3
Contents
Definition and basic Meanings Polymorphism and Dynamic Binding Polymorphism and Dynamic Binding i
n C++
4
Definition of Polymorphic
Polymorphous: Having, or assuming, various forms, characters, or styles. From greek routes, poly = many, and Morphos = form (Morphus was the greek god of sleep, who could assume many forms, and from which we derive the name Morphine, among other things).
A polymorphic compound can crystalize in many forms, such as carbon, which can be graphite, diamonds, or fullerenes.
In programming languages, used for a variety of different mechanisms.
5
Definition Polymorphism is a concept where a single name ma
y denote objects of different classes that are related by some common base class [Booch].
In polymorphic languages some values and variables may have more than one type
A function is polymorphic if it may be applied to arguments of different types
For example, several people in the class heard a big explosion (getting a message “explosion”), some shouted ”what’s the matter?” some rushed out the classroom for details, and some did not concerned about it. That is polymorphism!!!
6
Examples: Write a program to maintain a list of
shapes created by the user, and print the shapes when needed.
The shapes needed in the application are: points lines rectangles circles etc...
7
In Conventional Programs
You should write:if (Shape.type is circle) then
DrawCircle(Shape);else if (Shape.type is rectangle) then
DrawRectangle(Shape);else if (Shape.type is point) then
DrawPoint(Shape);else if( Shape.type is line) then
DrawLine(Shape);
8
Using Polymorphism
You need only to write: Shape.Draw() In Smalltalk, it is the case; But in C++, it is a pointer to Shape, then yo
u can set a pointer to the other shapes to the pointer Shape, at last ,you can use Shape->Draw();
Actually, the pointer in C++ is a type that can denote anything, such as, void * vp;
9
Major Forms of Polymorphism
There are four major forms of polymorphism in object-oriented languages: Overloading (ad hoc polymorphism) -- one name that
refers to two or more different implementations. Overriding (inclusion polymorphism) -- A child class
redefining a method inherited from a parent class. The Polymorphic Variable (assignment
polymorphism) -- A variable that can hold different types of values during the course of execution. It is called Pure Polymorphism when a polymorphic variable is used as a parameter.
Generics (or Templates) -- A way of creating general tools or classes by parameterizing on types.
10
Polymorphism and Overloading
It is realized by using a set of monomorphic functions. Different code is used for different types.
Two subtypes: Overloading means that the same operation
is implemented through different methods with the same function name. For different types, different implementations (methods) of the same operation are executed.
11
Polymorphism and Dynamic Binding
To implement polymorphism, a language must support dynamic binding. Polymorphism----- a concept Dynamic binding -----implementation
Why? With static binding, can you support a
polymorphism?
12
Polymorphism and Dynamic Binding
Classical paradigm function open_disk_file() function open_tape_file() function open_diskette_file()
Object-Oriented paradigm Function My_File.open_file() Correct method invoked at run-time (dynamically) Method open can be applied to objects of differen
t classes---Polymorphism
13
Negative Aspects
Negative impact on maintenance Hard to understand if multiple
possibilities for specific methods Note: Do not use the same name when
the methods have little similarities.
14
Polymorphism in C++
Virtual functions and polymorphism
Abstract and Concrete classes
15
Polymorphism in C++
It gives us the ability to manipulate instances of derived class through a set of operations defined in their base class.
Each derived class can implement the operations defined in the case class differently, while retaining a common class interface provided by the base class.
16
Polymorphism in C++
Virtual Function A non-static member function prefaced b
y the virtual specifier. It tells the compiler to generate code that
selects the appropriate version of this function at run time.
17
Example#include <iostream.h>class Employee {public: void Display(); // non-virtual virtual void CalcPaycheck(); // virtual};class SalariedEmployee :public Employee {public: void Display(); virtual void CalcPaycheck();};void Employee::CalcPaycheck(){cout << "Employee"<<"\n";}
18
Example
void SalariedEmployee::CalcPaycheck()
{cout << "SalariedEmployee"<<"\n";}
void Employee::Display()
{ CalcPaycheck(); }
void SalariedEmployee::Display()
{ CalcPaycheck();}
int main()
{ Employee * ep = new SalariedEmployee;
//...
ep->Display();
return 0;
}//salemp.cpp, Result: SalariedEmployee
19
Common Interface#include <iostream.h>
class Employee {
public:
long GetDepartment() const{return deptNum;};
long GetId() const{return id;};
void SetDepartment( long deptId ){};
void SetId(){};
virtual void CalcPaycheck() =0;
virtual void Input(){};
private:
long id;
long deptNum;
};
20
Common Interface
class SalariedEmployee :public Employee {public: Void CalcPaycheck(){cout<<"SalariedEmployee"<<endl;}; class HourlyEmployee :public Employee {public: void CalcPaycheck(){cout<<"HourlyEmployee"<<endl;}; void ProcessAnyEmployee( Employee & er ) { long anId = er.GetId(); // non-virtual er.CalcPaycheck(); // virtual } void main() {SalariedEmployee S; HourlyEmployee H; ProcessAnyEmployee( S ); ProcessAnyEmployee( H ); }//calcpay.cpp
21
Virtual Destructors
Calling the wrong destructor could be disastrous, particularly when it contains a delete statement.
Destructors are not inherited. It is wise to define one for each derived class.
Constructors inherited? No. Example:
22
Virtual Destructors#include <iostream.h>
class Item {
public:
Item(){id = 0;};
virtual ~Item(){ cout <<"Item deleted"<<endl;};
private:
int id;
};//virdes.cpp
23
Virtual Destructors class BookItem: public Item { public:
BookItem(){title = new char [50];}; virtual ~BookItem(){delete title;
cout <<"BookItem deleted"<<endl;}; private:
char * title;}; void main(){ Item * p;
p = new BookItem; delete p;
}
24
Abstract Classes An abstract class is a class that can
only be a base class for other classes.
Abstract classes represent concepts for which objects cannot exist.
A class that has no instances is an abstract class
Concrete Classes are used to instantiate objects.
25
An Abstract Class In C++, a class that has one or more vir
tual functions is an abstract class An abstract class either contains or inh
erits at least one pure virtual function. A pure virtual function is a virtual functi
on that contains a pure-specifier, designated by the “=0”.
26
Example:
Shape
Circle Polygon
27
The Class Shape#include <iostream.h>
class Point {
};
class Shape {
public:
virtual ~Shape(){};
virtual void Draw() const = 0;
virtual void MoveTo( int x2, int y2 ) = 0;
virtual void Rotate( int degrees ) = 0;
};//shape.cpp
28
class Circle :public Shape {public:
Circle(){};Circle( const Point & aCenter, float aRadius ){};
virtual ~Circle(){}; virtual void Draw() const{cout<<"Drawing!"<<endl;}; virtual void MoveTo( int x2, int y2) {cout<<"MoveTo"<<
endl;}; virtual void Rotate( int degrees) {cout<<"Rotate!"<<
endl;};private: Point center; float radius;};
Shape
29
Shapeclass Polygon :public Shape {public: Polygon(); Polygon( Point & cent, Point * verts ); virtual ~Polygon();private: Point center; Point * vertices; // array of Points};
30
Shape
int main()
{ Circle C;
C.Draw();
Point center;
Point vertices[10];
//Cannot create instance of abstract class Polygon:
// Polygon P( center, vertices );
return 0;
}//shape.cpp
31
An Abstract Derived Class
If in a derived class a pure virtual function is not defined, the derived class is also considered an abstract class.
When a derived class does not provide an implementation of a virtual function the base class implementation is used.
It is possible to declare pointer variables to abstract classes.
32
Compare with Java abstract classes
C++’s abstract classes are implicit, i.e., abstract classes contain pure virtual functions.
Java’s abstract classes are declared explicitly by the keyword “abstract”. In Java, you can even declare a non-abstract class as an abstract class, i.e., do not let it have instances.
Abstract classes cannot be instantiated in both C++ and Java.
33
Polymorphism in Java abstract class Employee { public Employee(String name) { setName(name); } public String getName() { return new String(name); } private void setName(String name) { this.name = new String(name); } abstract public double pay(); public String toString() { return "name is " + name; } private String name; } //Poly.java
34
Polymorphism in Java class Hourly extends Employee { public Hourly(String name, double rate, double hours) { super(name); setRate(rate); setHours(hours); } public void setRate(double rate) { this.rate = rate; } public void setHours(double hours) { this.hours = hours; } public double getRate() { return rate; } public double getHours() { return hours; } public double pay() { return rate * hours; } public String toString() { return super.toString() + “ (rate is " + rate + " and hours are
"+hours+ ')'; } private double rate; private double hours; }
35
Polymorphism in Java class Salaried extends Employee { public Salaried(String name, double salary) { super(name); setSalary(salary); } public void setSalary(double salary) {this.salary = salary; } public double getSalary() { return salary; } public double pay() { return salary; } public String toString() { return super.toString() + " (salary is " + salary + ")"; } double salary; }
36
Polymorphism in Java public class Poly { public static final int MAX_EMPLOYEES = 10; public static void main(String[] args) { Employee[] employees = new Employee[MAX_EMPLOYEES]; int emp = 0; employees[emp++] = new Hourly("George Jones", 75.00, 2.5); employees[emp++] = new Salaried("Dolly Parton", 125.00); employees[emp++] = new Hourly("Willie Nelson", 85.00, 3.0); employees[emp++] = new Salaried("Jim Reeves", 150.00); employees[emp++] = new Hourly("Tammy Wynette", 65.00,
2.0); for (int i = 0; i < emp; ++i) { System.out.println("employee: " + employees[i]); System.out.println("pay: " + employees[i].pay()); System.out.println(); } } }
37
Compare with C++’s Polymorphism
Java’s polymorphism is inherent. No specific keyword required. Java’s “abstract” is not the same as C+
+’s “virtual”. C++’s “virtual” is a must keyword for polym
orphism. Java’s “abstract” just shows that this meth
od should be implemented by the subclasses.
38
Summary of Polymorphism
One name, multiple meaning Overloading Overriding
Polymorphism and Dynamic Binding C++ Polymorphism
Virtual functions Java Polymorphism
39
Overloading
40
A Definition of Overloading
We say a term is overloaded if it has two or more meanings. Most words in natural languages are overloaded, and confusion is resolved by means of context.
Same is true of OO languages. There are two important classes of context that are used to resolve overloaded names Overloading based on Scopes Overloading based on Type Signatures
41
Resolving Overloaded Names
This type of overloading is resolved by looking at the type of the receiver. Allows the same name to be used in unrelated classes.
Since names need not be distinct, allows short, easy to remember, meaningful names.
42
Overloading Based on Type Signatures
A different type of overloading allows multiple implementations in the same scope to be resolved using type signatures.
class Example { // same name, three different methods int sum (int a) { return a; } int sum (int a, int b) { return a + b; } int sum (int a, int b, int c) { return a + b + c; } }
A type signature is the combination of argument types and return type. By looking at the signature of a call, can tell which version is intended.
43
Resolution Performed at Compile Time
Note that resolution is almost always performed at compile time, based on static types, and not dynamic values.
class Parent { ... }; class Child : public Parent { ... }; void Test(Parent * p) { cout << "in parent" << endl; } void Test(Child * c) { cout << "in child" << endl } Parent * value = new Child(); Test(value); Example will, perhaps surprisingly, execute parent
function.
44
Conversion and Coercions When one adds conversions into the mix,
resolving overloaded function or method calls can get very complex. Many different types of conversions: Implicit value changing conversion (such as
integer to real) Implicit conversion that does not change value
(pointer to child class converted into pointer to parent)
Explicit conversions (casts) Conversion operators (C++ and the like)
45
Redefinitions A redefinition occurs when a child class
changes the type signature of a method in the parent class. Two different types of rules are used to resolve name: The merge model. The scope of the child is
merged with the scope of the parent. The hierarchical model. Scopes are separate.
Search is made for first scope containing name, then for best fit within the scope.
46
Function Overloading It is the ability to give several functions
the same name provided the parameters for each of the functions differ in either: number type order
47
Function Overloading
A mechanism for multiple functions with the same name, it is the reflection to polymorphism.
In C++, a function is identified by not only the name but also the number, the order and the types of the parameters, which is called the signature.
48
Examples void swap (unsigned long &, unsigned
long &) void swap (double &, double &) void swap (char &, char &) void swap (Point &, Point &) They are different functions!!!
49
Argument Conversion
void calculate (long p1, long p2, double p3, double p4);
long a1 = 12345678; int a2 = 1; double a3 = 2.34567456; float a4 = 3.1; calculate(a1, a2, a3, a4); //Correct!!!
//Conversion! Assignment-compatible!!! Student S; calculate(S, 10, 5.5, 6)// Incompatible!!
50
Overloading Resolution
Best-matching function principle: For each argument, the compiler finds the
set of all functions that best match the parameter.
If more than one function results from the intersection, an error results.
51
Example
void display (int x); //version1 void display (float y); //version2 int i; float f; double d; display(i); //version1 display(f); //version2 display(d); // I do not know which one !!!
52
Another Example void print (float a, float b) {cout << “version1”<<endl;} void print (float a, int b) {cout << “version2”<<endl;}
53
Another Example main(){ int i, j; float f; double d; print (i,j); // version2 print (i,f); // version1 print (d,f); // version1}
54
Another Example
print (d,3.5); // error print (i,4.5); // error print (d,3.0); // error print (i,d); // errorBy Casting, you can get results. print (i,int(10L)); // version2 print (f,float(10L)); // version1 print (d,float(3.0)); // version1 print (i,int(d)); // version2, ex8-6.cpp
55
Inheritance and Overloading
Overloading in object-oriented programming is used when we hope to use the same name to express different functions that is kind of polymorphism.
Overloading is generally resolved by a function’s signature that is defined by the name, the parameter list of the function.
But in C++, overloading does not occur across scopes.
//overinh.cpp
56
Overloading in Javaclass Parent {
public void example (int a) { System.out.println("in parent method"); }
}class Child extends Parent {
public void example (int a) { System.out.println("in child method-1 int"); }//If deleted, it still works.public void example (int a, int b) { System.out.println("in child method-2 ints"); }public void example (int a, float b) { System.out.println("in child method-1 int and 1 float"); }public void example (float a, float b) { System.out.println("in child method-2 floats"); }
}public class Overload {
public static void main(String argv[]) {Parent p= new Parent();Child aChild = new Child();p.example(5);aChild.example(3);aChild.example(3, 5);aChild.example(3, 5.6f);p = aChild;p.example(5);}
}//Overload.java
57
Compare with C++’s overload
Java’s overload functions are among the base classes and subclasses.
In C++, there are no overload across scope, i.e., base classes and subclasses.
58
#include "stdafx.h"#include "iostream"using namespace std;class Parent {public:
void example (int a) { cout<<"in parent method"<<endl; }};class Child : public Parent {public:
void example (int a) { cout<<"in child method-1 int"<<endl; }//If deleted, it doesn’t work.void example (int a, int b) { cout<<"in child method-2 ints"<<endl; }void example (int a, float b) { cout<<"in child method-1 int and 1 float"<<endl; }void example (float a, float b) { cout<<"in child method-2 floats"<<endl; }
};int _tmain(int argc, _TCHAR* argv[]){ Parent *p= new Parent();
Child *aChild = new Child();p->example(5);aChild->example(3);aChild->example(3, 5);aChild->example(3, 5.6f);p = aChild;p->example(5);return 0;
}//OverloadAcrossClasses.cpp
59
Operator Overloading in C++
It refers to the technique of ascribing new meaning to standard operators such as +, >>, = … when used with class operands.
In fact, it is a way to name a function. Using the same name with some normal
operators, make the programming more readable.
60
Operator OverloadingIf you define an overloaded operator in class A
class:class Aclass{public:int operator +(Aclass &a){};}Aclass a, b; int i; i = a+b;// i = a.operator +(b);
61
Stream Output in C++ Stream output in C++ is a good example of the power of
overloading. Every primitive type has a different stream output function.
ostream & operator << (ostream & destination, int source); ostream & operator << (ostream & destination, short source); ostream & operator << (ostream & destination, long source); ostream & operator << (ostream & destination, char source); ostream & operator << (ostream & destination, char * source); // ... and so on double d = 3.14; cout << "The answer is " << d << '\n';
62
Easy to Extend Since output uses overloading, it is very easy to extend to new types. class Fraction { public: Fraction (int top, int bottom) { t = top; b = bottom; }
int numerator() { return t; } int denominator() { return b; }
private: int t, b; }; ostream & operator << (ostream & destination, Fraction & source) { destination << source.numerator() << "/" << source.denominator(); return destination; } Fraction f(3, 4); cout << "The value of f is " << f << '\n'; //ee.cpp
63
Example of Operator Overloading in C++
The ‘+’ symbol has been overloaded to represent: integer addition floating-point addition pointer addition
64
The Time Class
class Time { public: Time( unsigned c = 0 ); Time( const Time & t ); void SetHours( unsigned h ); void SetMinutes( unsigned m ); const Time & operator ++();//prefix operator Time operator ++(int);//postfix operator const Time & operator +=( unsigned n ); friend ostream & operator <<( ostream & os, const Time & h ); private: unsigned hours; unsigned minutes; };
65
The Time Class
Time::Time( unsigned tv ) //tv --1845..18:45 { SetHours(tv / 100); //quotient
SetMinutes(tv % 100); //remainder } Time::Time( const Time & t2 ) { minutes = t2.minutes; hours = t2.hours; }
66
The Time Class void Time::SetHours( unsigned h ) { if( h > HourMax ) throw RangeError(__FILE__,__LINE__,h); hours = h; }
void Time::SetMinutes( unsigned m )
{
if( m > MinuteMax ) throw RangeError(__FILE__,__LINE__,m);
minutes = m;
}
67
Overloading unary operators
const Time & Time::operator ++()//prefix { if( ++minutes > MinuteMax ) { minutes = 0; hours = (hours + 1) % (HourMax + 1); } return *this; }
68
Overloading unary operators
Time Time::operator ++( int )//postfix { Time save( *this ); // construct a copy operator ++(); // increment the time return save; // return the copy }
69
Overloading Binary Operators
const Time & Time::operator +=( unsigned n ) { unsigned t = minutes + n; minutes = t % (MinuteMax + 1); // remaining minutes hours += t / (MinuteMax + 1); // add to hours hours = hours % (HourMax + 1); // roll over to next day return *this; }
70
The Time Class
ostream & operator <<( ostream & os, const Time & t ) { os.fill('0'); os << setw(2) << t.hours << ':' << setw(2) <<
t.minutes; // os << t.hours << ':' << t.minutes<<', ' ; return os; }
71
void test(){ Time a;Time b(1845);Time c(2359);cout << ++a << '\n' // 00:01 << b++ << endl; // 18:45//operator <<(cout, b++);cout << (c += 15) << '\n' // 00:14//cout << c.operator += (15) << '\n'<< (b += 20) << '\n'; // 19:06Time d(1230);for(unsigned i = 0; i < 50; i++) cout << ++d << ", ";cout << endl;}
72
The Time Class
int main() { try { test(); } catch( const RangeError & R ) { cout << R; } return 0; }//ex8time.cpp
73
Summary
Function Overloading In C++, a function is identified by not only
the name but also the number, the order and the types of the parameters
Operator Overloading Be a way to name a function Be consistent with the uses of the operator
overloaded