+ All Categories
Home > Documents > 1 COSC3557: Object-Oriented Programming Haibin Zhu, Ph. D. Associate Professor of CS, Nipissing...

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

Date post: 31-Dec-2015
Category:
Upload: philip-turner
View: 218 times
Download: 0 times
Share this document with a friend
23
1 COSC3557: Object- Oriented Programming Haibin Zhu, Ph. D. Associate Professor of CS, Nipissing University
Transcript
Page 1: 1 COSC3557: Object-Oriented Programming Haibin Zhu, Ph. D. Associate Professor of CS, Nipissing University.

1

COSC3557: Object-Oriented Programming

Haibin Zhu, Ph. D.

Associate Professor of CS, Nipissing University

Page 2: 1 COSC3557: Object-Oriented Programming Haibin Zhu, Ph. D. Associate Professor of CS, Nipissing University.

2

Lecture 7

Overriding

Ref. : Chapter 16

Page 3: 1 COSC3557: Object-Oriented Programming Haibin Zhu, Ph. D. Associate Professor of CS, Nipissing University.

3

Difference from Overloading

Like overloading, there are two distinct methods with the same name. But there are differences: Overriding only occurs in the context of the

parent/child relationship The type signatures must match Overridden methods are sometimes

combined together Overriding is resolved at run-time, not at

compile time.

Page 4: 1 COSC3557: Object-Oriented Programming Haibin Zhu, Ph. D. Associate Professor of CS, Nipissing University.

4

Overriding Comparisons in Smalltalk

An interesting example of overriding is found in class Magnitude in Smalltalk.

<= arg^ self < arg or: [ self = arg ]

>= arg^ arg <= self

< arg^ self <= arg and: [ self ~= arg ]

> arg^ arg < self

= arg^ self == arg

~= arg^ (self == arg) not

Notice how these definitions are circular.

Page 5: 1 COSC3557: Object-Oriented Programming Haibin Zhu, Ph. D. Associate Professor of CS, Nipissing University.

5

Subclasses of Magnitude in Little Smalltalk

Page 6: 1 COSC3557: Object-Oriented Programming Haibin Zhu, Ph. D. Associate Professor of CS, Nipissing University.

6

Overridden Relations Child classes need only override one method

(for example <) to get effect of all relational. Overridden in class Integer to mean integer less

than. Overridden in class Char to be ASCII ordering

sequence. Overridden in class String to mean lexical-graphic

ordering. Overridden in class Point to mean lower-left

quadrant.

Page 7: 1 COSC3557: Object-Oriented Programming Haibin Zhu, Ph. D. Associate Professor of CS, Nipissing University.

7

Notating Overriding Generally, for instances, overriding occurs automatically. For references (or pointers), in some languages (Smalltalk, Java)

overriding occurs automatically when a child class redefines a method with the same name and type signature. In some languages (C++) overriding will only occur if the parent class has declared the method in some special way (example, keyword virtual).

In some languages (Object Pascal) overriding will only occur if the child class declares the method in some special way (example, keyword override).

In some languages (C#, Delphi) overriding will only occur if both the parent and the child class declare the method in some special way. class Parent { // C# example public virtual int example (int a) { ... } } class Child : Parent { public override int example (int a) { ... } }

Page 8: 1 COSC3557: Object-Oriented Programming Haibin Zhu, Ph. D. Associate Professor of CS, Nipissing University.

8

Replacement and Refinement

There are actually two different ways that overriding can be handled: A replacement totally and completely replaces the

code in the parent class the code in the child class.

A refinement executes the code in the parent class, and adds to it the code in the child class.

Most languages use both types of semantics in different situations. Constructors, for example, almost always use refinement.

Page 9: 1 COSC3557: Object-Oriented Programming Haibin Zhu, Ph. D. Associate Professor of CS, Nipissing University.

9

Reasons to use Replacement

There are a number of reasons to use replacement of methods. The method in the parent class is abstract, it

must be replaced. The method in the parent class is a default

method, not appropriate for all situations. The method in the parent can be more

efficiently executed in the child.

Page 10: 1 COSC3557: Object-Oriented Programming Haibin Zhu, Ph. D. Associate Professor of CS, Nipissing University.

10

Overriding a Default Method

Here is another from Smalltalk. Class Number has child classes Integer, Fraction and Float. Method in class Number is defined as follows: "class Number" sqrt ^ self asFloat sqrt

The method in class Float clearly must perform something different, in this case actually computing the square root. The parent class has a method that will work in most, but not all, child classes.

Page 11: 1 COSC3557: Object-Oriented Programming Haibin Zhu, Ph. D. Associate Professor of CS, Nipissing University.

11

Overriding for Optimization Here is an example where a child class can do the same action more

efficiently than the parent class. Class Boolean has child classes True and False, and defines the following methods:

"class Boolean"

& right self ifTrue: [ right ifTrue: [ ^ true ] ]. ^ false

| right self ifTrue: [ ^ true ]. right ifTrue: [ ^ true ]. ^ false

These very general algorithms will work for either true or false values.

Page 12: 1 COSC3557: Object-Oriented Programming Haibin Zhu, Ph. D. Associate Professor of CS, Nipissing University.

12

More Efficient Versions in class True

In class True we know the left argument is true, and therefore can make more efficient algorithms.

" class True "

& right ^ right

| right ^ true

Similar code in class False. These are faster than the code in the parent class, but have the same effect.

Page 13: 1 COSC3557: Object-Oriented Programming Haibin Zhu, Ph. D. Associate Professor of CS, Nipissing University.

13

Downside of Replacement The down side of replacement semantics is

that there is no guarantee that the child class will have any meaning at all similar to the parent class. For example, a child class could redefine sqrt to

compute the cube root of its argument. This goes back to the difference between

subclasses and subtypes. A refinement makes this difficult to do, since

whatever the parent does is guaranteed to be part of the child. This is why most languages use refinement semantics for constructors.

Page 14: 1 COSC3557: Object-Oriented Programming Haibin Zhu, Ph. D. Associate Professor of CS, Nipissing University.

14

Simulating Refinement with Replacement

In most languages the most important features of a refinement can be simulated, even if the language uses replacement. void Parent::example (int a) { cout << "in parent code\n"; }

void Child::example (int a) { Parent::example(12); // do parent code cout << "in child code\n"; // then child code }

Page 15: 1 COSC3557: Object-Oriented Programming Haibin Zhu, Ph. D. Associate Professor of CS, Nipissing University.

15

Constructors use Refinement

In most languages that have constructors, a constructor will always use refinement.

This guarantees that whatever initialization the parent class performs will always be included as part of the initialization of the child class.

Page 16: 1 COSC3557: Object-Oriented Programming Haibin Zhu, Ph. D. Associate Professor of CS, Nipissing University.

16

Overriding versus Shadowing

It is common in programming languages for one declaration of a variable to shadow a previous variable of the same name:

class Silly { private int x; // an instance variable named x

public void example (int x) { // x shadows instance variable int a = x+1; while (a > 3) { int x = 1; // local variable shadows

parameter a = a - x; } } }

Page 17: 1 COSC3557: Object-Oriented Programming Haibin Zhu, Ph. D. Associate Professor of CS, Nipissing University.

17

Shadowing of Instance Variables in Java

Java allows instance variables to be redefined, and uses shadowing. class Parent { public int x = 12; public int get() {return x;}; } class Child extends Parent { public int x = 42; // shadows variable from parent class public int get() {return x;}; } public class override { public static void main(String args[]) { Parent p = new Parent(); Child c= new Child(); System.out.println("p.x is "+p.x+" and c.x is " +c.x); p = c; System.out.println("p.x is "+p.x+" and c.x is " +c.x); System.out.println("p.x is "+p.get()+" and c.x is " +c.get()); } }//override.java

Page 18: 1 COSC3557: Object-Oriented Programming Haibin Zhu, Ph. D. Associate Professor of CS, Nipissing University.

18

Shadowing Methods Many of those languages that require the virtual keyword in the parent class will use

shadowing if it is omitted: class Parent { public: // note, no virtual keyword here void example () { cout << "Parent" << endl; } };

class Child : public Parent { public: void example () { cout << "Child" << endl; } };

Parent * p = new Parent(); p->example() //Parent

Child * c = new Child(); c->example() //Child

p = c; // be careful here! p->example() //Parent //override.cpp

Page 19: 1 COSC3557: Object-Oriented Programming Haibin Zhu, Ph. D. Associate Professor of CS, Nipissing University.

19

Overriding, Shadowing and Redefinition

Overriding The type signatures are the same in both parent and child

classes, and the method is declared as virtual in the parent class.

Shadowing

The type signatures are the same in both parent and child classes, but the method was not declared as virtual in the parent class.

Redefinition The type signature in the child class differs

from that given in the parent class.

Page 20: 1 COSC3557: Object-Oriented Programming Haibin Zhu, Ph. D. Associate Professor of CS, Nipissing University.

20

Covariance and Contravariance

Frequently it seems like it would be nice if when a method is overridden we could change the argument types or return types. A change that moves down the inheritance hierarchy, making it more specific, is said to be covariant. A change that moves up the inheritance hierarchy is said to be contravariant.

class Parent { void test (covar : Mammal, contravar : Mammal) :

boolean } class Child extends Parent { void test (covar : Cat, contravar : Animal) : boolean } While appealing, this idea runs into trouble with the principle of

substitution. Parent aValue = new Child(); aValue.text(new Dog(), new Mammal()); // is this legal??

Page 21: 1 COSC3557: Object-Oriented Programming Haibin Zhu, Ph. D. Associate Professor of CS, Nipissing University.

21

Contravariant Return Types

To see how a contravariant change can get you into trouble, consider changing the return types:

class Parent { Mammal test ( ) { return new Cat(); } }

class Child extends Parent { Animal test () { return new Bird(); } }

Parent aParent = new Child(); Mammal result = aParent.test(); // is this legal? //Covar.java Most languages subscribe to the novariance rule: no change in type signatures.

Page 22: 1 COSC3557: Object-Oriented Programming Haibin Zhu, Ph. D. Associate Professor of CS, Nipissing University.

22

A Safe Variance Change C++ allows the following type of change in signature: class Parent { public: Parent * clone () { return new Parent(); } };

class Child : public Parent { public: Child * clone () { return new Child(); } }; //sig.cpp No type errors can result from this change.

Page 23: 1 COSC3557: Object-Oriented Programming Haibin Zhu, Ph. D. Associate Professor of CS, Nipissing University.

23

Summary An override occurs when a method in the child classes

uses the same name and type signature as a method in the parent class.

Unlike overloading, overriding is resolved at run-time. There are two possible means for an overriding,

replacement and refinement. A name can shadow another name. Some languages

permit both shadowing and overriding. Shadowing is resolved at compile time.

A change in the type signature can be covariant or contravariant, if it moves down or up the type hierarchy. The semantics of both types of change can be subtle.


Recommended