1 COSC3557: Object-Oriented Programming Haibin Zhu, Ph. D. Assistant Professor of CS, Nipissing...

Preview:

Citation preview

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

Recommended