Vous êtes sur la page 1sur 15

Dynamic Binding

Object-Oriented Programming

236703

Spring 2008

Non-Strict Inheritance

AKA Inheritance

More Powerful Abstraction Mechanism: a subclass is just like the superclass, except for an explicit list of changes:

Additional operations.

Additional structure elements.

Operations implemented differently, also called overridden operations.

Note: there is usually no way to “re-implement” structure elements.

Binding Time

Binding: linking between messages and methods

Compile Time

Link Time

Execution Time:

Program Init

Procedure/function begin

Statement Execution

Inclusion Polymorphism: The same entity may refer to objects of different classes, each of which has a different implementation of the same method

Inclusion Polymorphism + Overriding = Binding Question

Static Binding (AKA Early Binding): the compiler uses the type of variables to do the binding at a compile (link) time

Dynamic Binding (AKA Late Binding): the decision is made at run time based on the type of the actual values

Static vs. Dynamic Types

Employee print +
Employee
print +
Static vs. Dynamic Types Employee print + Manager print ++ • Consider the call: Employee* e->print();
Static vs. Dynamic Types Employee print + Manager print ++ • Consider the call: Employee* e->print();
Manager print ++
Manager
print ++

Consider the call:

Employee*

e->print();

e = new Manager();

What is the type of e?

Static Type:

Employee *

What can be determined in compile time

Dynamic Type:

Manager *

Actual type, as determined in run time

Which version of print will be called?

Based on the static type? or,

Based on the dynamic type?

Dynamic Binding and Static Typing

Static typing: guarantee that a method exists

A variable of type T can contain only objects of type T, or of type T', where T' is derived from T.

A message to an object is legal only if its static type recognizes it.

Dynamic binding: make sure that the right method is selected.

The method invoked for an object depends on its dynamic type.

Static typing + Dynamic binding: the right combination of safety and power

Examples: Eiffel, C++, Java, Object-Pascal, Turbo- Pascal, etc.

C++ Example

C++ Example struct Base { }; virtual void f() { void g() { } struct Derived:

struct Base {

};

virtual void f() {

void g() {

}

struct Derived: Base { virtual void f() {

}

} // Override f() of Base

void g() {

}

// Override g() of Base

void h() {

}

} y;

Base *px = &y;

px->f();

px->g();

px->h();

// The right method // The wrong method // Compile time error! No guarantee that the method exists

Java Example

public class X { public String toString() { return "X"; } public final int addThree(int n) {return n+3; } public static int mul(int a, int b) {return a*b; }

}

public class Y extends X

{

What's the binding of super.toString()?

public final String toString() { return "Y" + super.toString();

{

}

X x = new X(); x.toString(); x.addThree(5); x.mul(3,9);
X x = new X();
x.toString();
x.addThree(5);
x.mul(3,9);
Y y = new Y(); y.toString(); y.addThree(5); y.mul(3,9);
Y y = new Y();
y.toString();
y.addThree(5);
y.mul(3,9);
X x = new Y(); x.toString(); x.addThree(5); x.mul(3,9);
X x = new Y();
x.toString();
x.addThree(5);
x.mul(3,9);

Downcasting vs. Dynamic Binding

void draw(Shape *p)

{

if (Circle *q = dynamic_cast<Circle *>p) { // Draw circle

} else if (Line *q = dynamic_cast<Line *>p) { // Draw line

} else if (Rectangle *q = dynamic_cast<Rectangle *>p) { // Draw rectangle

}

}

RTTI considered harmful:

Order of classes in the if chains is significant

Module must change whenever new class is added to the hierarchy

Forms of Overriding

Replacement: The new implementation of an operation replaces the implementation of the operation in the base class.

The only kind of overriding in earlier versions of Eiffel.

Refinement: The new implementation of an

operation refines the implementation of the operation in the base class. It reuses the code of the overridden method. Usually:

Overriding method calls inherited method

Just like using:

super in Smalltalk, Java

Inherited in Turbo-Pascal 7.0

Precursor in Eiffel

Kinds of Refinement

Alpha refinement: the overriding operation calls the overridden operation.

C++, Smalltalk, Java

Beta refinement: the overridden operation must call the overriding version explicitly.

Excludes replacement! If the implementation in the superclass does not execute an inner command, then the implementation in the subclass is not executed.

Better guarantee of conformance.

Simula, BETA.

Alpha Refinement and Subobjects

Recall that each object of a subclass has a subobject of the superclass.

This subobject may have in turn other sub-subobjects in it.

Alpha refinement involves a forwarding of the message to the subobject.

Mechanisms for forwarding to subobject:

Smalltalk and Objective-C: super pseudo-variable refers to largest contained subobject.

Object and Turbo Pascal: Inherited keyword refers to the class in which the overridden method was defined.

Eiffel: Precursor keyword.

C++: Must use scope resolution operator explicitly

class CheckedArray: public Array {

explicit CheckedArray(int len): Array(len) {}

};

resolution operator explicitly class CheckedArray: public Array { explicit CheckedArray(int len): Array(len) {} };

Beta Refinement

Advantage: The working of the subclass bears more resemblance with that of the superclass.

Disadvantages:

The designer of an overriding method must be intimately familiar with the workings of the overridden method.

The inner keyword cannot be overridden.

Pseudo C++ Examples:

keyword cannot be overridden. • Pseudo C++ Examples: struct Window { virtual void draw(void) { //
struct Window { virtual void draw(void) { // Set clipping region inner; // Restore clipping
struct Window {
virtual void draw(void)
{
// Set clipping region
inner;
// Restore clipping region
{
}
};
region inner; // Restore clipping region { } }; struct Object { virtual bool print(void) if

struct Object {

virtual bool print(void)

if (inner) return; cout << "an object"; return false;

};

}

Beta Refinement in Flavors

before and after daemons:

Called before and after the overriding method

The more general ones daemons wrap around the more specific ones, with the primary method, in the middle

It is possible, in principle, to define daemons also for daemons!

Example: FramedWindow subclassOf: Window methods:

after draw [self drawFrame]

TitledFrameWindow subclassOf: FramedWindow methods:

after draw [self drawTitle]

Alpha Refinement a-la Flavors

Wrappers:

Just like daemons, but defined in the subclass.

More powerful than super since multiple wrappers will nest appropriately, even if an overriding method down the inheritance hierarchy fails to invoke the overridden method.

Main drawback:

Confusing semantics!

Programmer Defined Combination

In Flavors, it is possible to define a method combination facility, using the full generality of Lisp:

Class: Military

methods:

generic totalFuelSupply: fuelType [methodCombination: sum]

generic totalFuelSupply: fuelType [methodCombination: sum] totalFuelSupply: fuelType [ ] Class: Army subclassOf:

totalFuelSupply: fuelType [

]

Class: Army subclassOf: Military methods:

totalFuelSupply: fuelType [

]