7: Polymorphism Upcasting revisited Forgetting the object type

Slides:



Advertisements
Similar presentations
Overriding CMPS Overriding Recall, a method in a child class overrides a method in the parent class, if it has the same name and type signature.
Advertisements

A subclass can add new private instance variables A subclass can add new public, private or static methods A subclass can override inherited methods A.
Big Ideas behind Inheritance. Can you think of some possible examples of inheritance hierarchies?
Chapter 7: Polymorphism ● Polymorphism is the thrid essential feature of OOP – You know the other two already: Data Abstraction and Inheritance ● It helps.
. Virtual Classes & Polymorphism. Example (revisited) u We want to implement a graphics system u We plan to have lists of shape. Each shape should be.
Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes.
Jan Object Oriented Programming Yangjun Chen Dept. Business Computing University of Winnipeg.
Object-Oriented Programming MISM/MSIT Carnegie Mellon University Lecture 4: Polymorphism.
Polymorphism What is Polymorphism? Taking Advantage of Polymorphism
1 Lecture 4 Further OO Concepts I - Polymorphism Overview  What is polymorphism?  Why polymorphism is wonderful?  Why is Upcasting useful?  What is.
Inheritance and Polymorphism Recitation – 10/(16,17)/2008 CS 180 Department of Computer Science, Purdue University.
1 Further OO Concepts (Part I) Further OO Concepts I - Polymorphism Overview l Polymorphism is Wonderful. l Usefulness of Up casting? l Method call binding?
Java Interfaces Overview Java Interfaces: A Definition.
OOP Etgar 2008 – Recitation 71 Object Oriented Programming Etgar 2008 Recitation 7.
Polymorphism &Virtual Functions
Overview of Previous Lesson(s) Over View  OOP  A class is a data type that you define to suit customized application requirements.  A class can be.
Exception Jiafan Zhou. Java Exception Handling Exception = an event that occurs during the execution of a program that disrupts the normal flow of instructions:
Comp 249 Programming Methodology Chapter 8 - Polymorphism Dr. Aiman Hanna Department of Computer Science & Software Engineering Concordia University, Montreal,
JAVA Introduction ● One of the main JAVA design goal is reducing complexity for programmer – Development time is half or less comparing to equivalent C++
Programming With Java ICS201 University Of Ha’il1 Chapter 8 Polymorphism and Abstract Classes.
CS212: Object Oriented Analysis and Design Lecture 15: Inheritance in C++ -II.
Inheritance - Polymorphism ITI 1121 Nour El Kadri.
1 Inheritance. 2 Why use inheritance?  The most important aspect of inheritance is that it expresses a relationship between the new class and the base.
Polymorphism. 3 main programming mechanisms that constitute OOP: 1. Encapsulation 2. Inheritance 3. Polymorphism.
Chapter 3 Inheritance and Polymorphism Goals: 1.Superclasses and subclasses 2.Inheritance Hierarchy 3.Polymorphism 4.Type Compatibility 5.Abstract Classes.
Chapter 10 Inheritance and Polymorphism
Programming in Java CSCI-2220 Object Oriented Programming.
Reusing Classes composition The trick is to use the classes without soiling the existing code. In this chapter you’ll see two ways to accomplish.
Programming With Java ICS201 University Of Ha’il1 Chapter 7 Inheritance.
Object Oriented Programming
CS212: Object Oriented Analysis and Design Lecture 16: Runtime Polymorphism.
Peyman Dodangeh Sharif University of Technology Fall 2014.
CMSC 202 Polymorphism. 10/20102 Topics Binding (early and late) Upcasting and downcasting Extensibility The final modifier with  methods  classes.
Polymorphism and Virtual Functions One name many shapes behaviour Unit - 07.
Computer Science Department Inheritance & Polymorphism.
CSCI-383 Object-Oriented Programming & Design Lecture 17.
1 Tirgul 8 Inheritance and Polymorphism. 2 Inheritance and Polymorphism An important part of Object Oriented Programming. Very often misused by beginners.
Design issues for Object-Oriented Languages
Inheritance Modern object-oriented (OO) programming languages provide 3 capabilities: encapsulation inheritance polymorphism which can improve the design,
Polymorphism in Methods
Modern Programming Tools And Techniques-I
CMSC 202 Polymorphism.
Advanced Programming in Java
Inheritance and Polymorphism
Object-Oriented Programming
Polymorphism.
CS212: Object Oriented Analysis and Design
JAVA Introduction ការណែនាំពី Java
Inheritance & Polymorphism
Polymorphism & Virtual Functions
Comp 249 Programming Methodology
ATS Application Programming: Java Programming
Object Oriented Programming
OOP’S Concepts in C#.Net
More inheritance, Abstract Classes and Interfaces
Virtual Functions Department of CSE, BUET Chapter 10.
CMSC 202 Polymorphism.
Polymorphism Polymorphism
CS18000: Problem Solving and Object-Oriented Programming
9: POLYMORPHISM Programming Technique II (SCSJ1023) Jumail Bin Taliba
Polymorphism CMSC 202, Version 4/02.
Polymorphism.
Chapter 9 Carrano Chapter 10 Small Java
Polymorphism 2019/4/29.
Creating and Modifying Text part 3
Java Programming: From the Ground Up
C++ Object Oriented 1.
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.
Computer Science II for Majors
INTERFACES Explained By: Sarbjit Kaur. Lecturer, Department of Computer Application, PGG.C.G., Sector: 42, Chandigarh.
Presentation transcript:

7: Polymorphism Upcasting revisited Forgetting the object type The twist Method-call binding Producing the right behavior Extensibility Overriding vs. overloading Abstract classes and methods Constructors and polymorphism Designing with inheritance Exercises

7: Polymorphism Polymorphism is the third essential feature of an object-oriented programming language, after data abstraction and inheritance.

7: Polymorphism class Note { private int value; private Note(int val) { value = val; } public static final Note MIDDLE_C = new Note(0), C_SHARP = new Note(1), B_FLAT = new Note(2); } // Etc. class Instrument { public void play(Note n) { System.out.println("Instrument.play()"); } // Wind objects are instruments // because they have the same interface: class Wind extends Instrument { // Redefine interface method: public void play(Note n) { System.out.println("Wind.play()"); } public class Music { public static void tune(Instrument i) { i.play(Note.MIDDLE_C); public static void main(String[] args) { Wind flute = new Wind(); tune(flute); // Upcasting

The twist The difficulty with Music.java can be seen by running the program. The output is Wind.play( ). This is clearly the desired output, but it doesn’t seem to make sense that it would work that way. Look at the tune( ) method: public static void tune(Instrument i) { // ... i.play(Note.MIDDLE_C); } It receives an Instrument reference. So how can the compiler possibly know that this Instrument reference points to a Wind in this case and not a Brass or Stringed? The compiler can’t.

Method-call binding Connecting a method call to a method body is called binding. early binding: When binding is performed before the program is run (by the compiler and linker) You might not have heard the term before because it has never been an option with procedural languages. C compilers have only one kind of method call, and that’s early binding. late binding: means that the binding occurs at run-time based on the type of object. Late binding is also called dynamic binding or run-time binding. There must be some mechanism to determine the type of the object at run-time and to call the appropriate method. The compiler still doesn’t know the object type.

Producing the right behavior The classic example in OOP is the “shape” example. This is commonly used because it is easy to visualize.

class Shape { void draw() {} void erase() {} } class Circle extends Shape { void draw() { System.out.println("Circle.draw()"); } void erase() { System.out.println("Circle.erase()"); } class Square extends Shape { void draw() { System.out.println("Square.draw()"); } void erase() { System.out.println("Square.erase()"); } class Triangle extends Shape { void draw() { System.out.println("Triangle.draw()"); } void erase() { System.out.println("Triangle.erase()"); } public class Shapes { public static Shape randShape() { // Upcasting switch((int)(Math.random() * 3)) { default: case 0: return new Circle(); case 1: return new Square(); case 2: return new Triangle(); } public static void main(String[] args) { Shape[] s = new Shape[9]; // Fill up the array with shapes: for(int i = 0; i < s.length; i++) s[i] = randShape(); // Make polymorphic method calls: for(int i = 0; i < s.length; i++) s[i].draw(); } ///:~ Circle.draw() Triangle.draw() Circle.draw() Circle.draw() Circle.draw() Square.draw() Triangle.draw() Square.draw() Square.draw()

Exercise ========= public class Shapes main class Shape { void draw() {} void erase() {} void flash() { draw(); erase(); draw(); } } class Circle extends Shape { void draw() { System.out.println("Circle.draw()"); } void erase() { System.out.println("Circle.erase()"); } class Square extends Shape { void draw() { System.out.println("Square.draw()"); } void erase() { System.out.println("Square.erase()"); } class Triangle extends Shape { void draw() { System.out.println("Triangle.draw()"); } void erase() { System.out.println("Triangle.erase()"); } ========= public class Shapes main for(int i = 0; i < s.length; i++) s[i]. flash();

Extensibility Because of polymorphism, you can add as many new types as you want to the system without changing the tune( ) method. All these new classes work correctly with the old, unchanged tune( ) method.

import java.util.*; class Instrument { public void play() { System.out.println("Instrument.play()"); } public String what() { return "Instrument"; } public void adjust() {} } ===================== class Wind extends Instrument { public void play() { System.out.println("Wind.play()"); } public String what() { return "Wind"; } class Percussion extends Instrument { public void play() { System.out.println("Percussion.play()"); } public String what() { return "Percussion"; } class Stringed extends Instrument { ……} class Woodwind extends Wind { ……} class Brass extends Wind { ……} ========================== public class Music3 { // Doesn't care about type, so new types static void tune(Instrument i) { // ... i.play(); } static void tuneAll(Instrument[] e) { for(int i = 0; i < e.length; i++) tune(e[i]); } public static void main(String[] args) { Instrument[] orchestra = new Instrument[5]; int i = 0; // Upcasting during addition to the array: orchestra[i++] = new Wind(); orchestra[i++] = new Percussion(); orchestra[i++] = new Stringed(); orchestra[i++] = new Brass(); orchestra[i++] = new Woodwind(); tuneAll(orchestra); } ///:~

Overriding vs. overloading class NoteX { public static final int MIDDLE_C = 0, C_SHARP = 1, C_FLAT = 2; } class InstrumentX { public void play(int NoteX) { System.out.println("InstrumentX.play()"); class WindX extends InstrumentX { // OOPS! Changes the method interface: public void play(NoteX n) { System.out.println("WindX.play(NoteX n)"); } public class WindError { public static void tune(InstrumentX i) { i.play(NoteX.MIDDLE_C); } public static void main(String[] args) { WindX flute = new WindX(); tune(flute); // Not the desired behavior! } ///:~

Abstract classes and methods In above examples, the methods in the base class Instrument were always “dummy” methods. If these methods are ever called, you’ve done something wrong. The intent of Instrument is to create a common interface for all the classes derived from it. Java provides a mechanism for doing this called the abstract method. A class containing abstract method is a abstract class. abstract method is a method that is incomplete; it has only a declaration and no method body. abstract void f(); It cannot create an object of an abstract class If you inherit from an abstract class and you want to make objects of the new type, you must override (redefine) all the abstract methods in the base class. If you don’t (and you may choose not to), then the derived class is also abstract.

Abstract classes and methods import java.util.*; abstract class Instrument { int i; // storage allocated for each public abstract void play(); public String what() { return "Instrument"; } public abstract void adjust(); } class Wind extends Instrument { public void play() { System.out.println("Wind.play()"); public String what() { return "Wind"; } public void adjust() {}

Designing with inheritance Once you learn about polymorphism, it can seem that everything ought to be inherited because polymorphism is such a clever tool. This can burden your designs; A better approach is to choose composition first, when it’s not obvious which one you should use. A Stage object contains a reference to an Actor, which is initialized to a HappyActor object. At run-time, a reference for a SadActor object can be substituted in a and then the behavior produced by go( ) changes. Thus you gain dynamic flexibility at run-time. (This is also called the State Pattern. )

Designing with inheritance // Dynamically changing the behavior of // an object via composition. abstract class Actor { abstract void act(); } class HappyActor extends Actor { public void act() { System.out.println("HappyActor"); } class SadActor extends Actor { public void act() { System.out.println("SadActor"); } class Stage { Actor a = new HappyActor(); void change() { a = new SadActor(); } void go() { a.act(); } public class Transmogrify { public static void main(String[] args) { Stage s = new Stage(); s.go(); // Prints "HappyActor" s.change(); s.go(); // Prints "SadActor" } ///:~

Downcasting and run-time type identification While upcasting is a useful and sensible approach (depending on the situation) it has a drawback. The extended part of the interface in the derived class is not available from the base class, so once you upcast you can’t call the new methods:

Downcasting and run-time type identification import java.util.*; class Useful { public void f() {} public void g() {} } class MoreUseful extends Useful { public void u() {} public void v() {} public void w() {} import java.util.*; public class RTTI { public static void main(String[] args) { Useful[] x = { new Useful(), new MoreUseful() }; x[0].f(); x[1].g(); // Compile-time: method not found in Useful: //! x[1].u(); // Downcast/RTTI ((MoreUseful)x[1]).u(); // Exception thrown ((MoreUseful)x[0]).u(); } } ///:~

Downcasting and run-time type identification Since you lose the specific type information via an upcast (moving up the inheritance hierarchy), you can use a downcast to retrieve the type information (moving down the inheritance hierarchy ) An upcast is always safe; the base class cannot have a bigger interface than the derived class, therefore every message you send through the base class interface is guaranteed to be accepted. But a downcast is unsafe, A shape (for example) may be a circle or a triangle or a square or some other type. In Java every cast is checked! At run-time this cast is checked to ensure that it is in fact the type you think it is. If it isn’t, you get a ClassCastException. This act of checking types at run-time is called run-time type identification (RTTI).