Lecture 24: Dynamic Binding

advertisement
CSCI 431 Programming Languages
Fall 2003
Dynamic Binding
(Section 10.4)
A compilation of material developed by Felix
Hernandez-Campos and Mircea Nicolescu
1
Fundamental Concepts in OOP
• Encapsulation
– Data Abstraction
– Information hiding
– The notion of class and object
• Inheritance
– Code reusability
– Is-a vs. has-a relationships
• Polymorphism
– Dynamic method binding
2
Inheritance
• Encapsulation improves code reusability
– Abstract Data Types
– Modules
– Classes
• However, it is generally the case that the code a
programmer wants to reuse is close but not exactly
what the programmer needs
• Inheritance provides a mechanism to extend or
refine units of encapsulation
– By adding or overriding methods
– By adding attributes
3
Inheritance
Notation
Java.awt.Dialog
Base Class
(or Parent Class
or Superclass)
Is-a relationship
Java.awt.FileDialog
Derived Class
(or Child Class
or Subclass)
4
Dynamic Method Binding
• Consequence of inheritance
– derived class D has all members of its base class B
– can use an object of class D everywhere an object of class B is expected
» a form of polymorphism
• Example (C++):
class person { ... };
class student : public person { ... };
class professor : public person { ... };
student s;
professor p;
...
person * x = &s;
person * y = &p;
// Both student and professor objects have all properties of
// a person object
// Both can be used in a person context
5
Dynamic Method Binding
• Example (C++):
class person { ... };
class student : public person { ... };
class professor : public person { ... };
void person::print_mailing_label () { ... }
student s;
professor p;
...
person * x = &s;
person * y = &p;
s.print_mailing_label ();
p.print_mailing_label ();
// person::print_mailing_label ()
// person::print_mailing_label ()
6
Dynamic Method Binding
• Example (C++):
– Suppose that we redefine print_mailing_label in both derived classes
void student::print_mailing_label () { ... }
void professor::print_mailing_label () { ... }
student s;
professor p;
...
person * x = &s;
person * y = &p;
s.print_mailing_label ();
p.print_mailing_label ();
// student ::print_mailing_label ()
// professor ::print_mailing_label ()
– But what about:
x->print_mailing_label ();
y->print_mailing_label ();
// ??
// ??
7
Dynamic Method Binding
• Example (C++):
– Two alternatives for choosing the
method to call:
student s;
professor p;
...
person * x = &s;
person * y = &p;
x->print_mailing_label ();
y->print_mailing_label ();
// ??
// ??
» according to the types of variables (references) x and y – static method binding
(will call the method of person in both cases)
» according to the types of objects s and p to which x and y refer – dynamic
method binding (will call the methods of student / professor)
– Dynamic method binding – central issue to object-oriented programming
– Example – list of persons that have overdue library books
» list may contain both students and professors
» traverse the list and print a mailing label - call the appropriate subroutine
8
Dynamic Method Binding
• Disadvantage of dynamic method binding
– run-time overhead
• Smalltalk, Modula-3
– dynamic method binding
• Java, Eiffel
– dynamic method binding by default
– individual methods can be labeled final (Java) or frozen (Eiffel)
» cannot be overriden by derived classes
» use static method binding
• Simula, C++, Ada 95
– static method binding by default
– how do we specify dynamic binding in C++?
» label individual methods as virtual
9
Virtual and Non-Virtual Methods
• Terminology in C++:
– redefine a method that uses static binding
– override a method that uses dynamic binding
• C++
class person
{
public:
virtual void print_mailing_label ();
...
}
– if print_mailing_label is overridden in classes student and professor
» at run time, the appropriate one is chosen – dynamic binding
10
Virtual and Non-Virtual Methods
• Ada
– methods take as parameter the object they are applied to
– dynamic binding is associated not with the method but with the parameter
– here, r needs to be declared as person'Class → dynamic binding
11
Virtual and Non-Virtual Methods
• Static method binding is more efficient
• When could it be undesirable?
– May not preserve consistency in the derived class
– Example:
class text_file
{
char * name;
long crt_pos;
public:
void seek (long pos);
...
};
// non-virtual
class read_ahead_text_file : public text_file
{
char * upcoming_chars;
public:
void seek (long pos);
// redefinition
// also updates the upcoming_chars
...
};
– with static binding:
» text_file::seek may be called for a read_ahead_text_file object, if used where
text_file was expected
» state of the read_ahead_text_file object would become inconsistent
12
Abstract Classes
• C++
class person
{
...
public:
virtual void print_mailing_label () = 0;
...
};
– Abstract method – virtual method with no body
» also called pure virtual method in C++
– Abstract class – it has at least one abstract method
» cannot declare objects of an abstract class, just pointers
– Purpose of an abstract class:
» serve as base to derive concrete classes
» a concrete class must provide a definition for every abstract method it inherits
– Interface (Java) –
class with no other members than abstract methods
13
Member Lookup
• Static method binding:
– easy to find the method to call, based on the type of the variable
– performed at compile time
• Dynamic method binding
– appropriate method is identified at run-time
– objects must contain information to allow for finding the appropriate
method
– each object contains a pointer to a virtual method table (vtable)
– all objects of a given class have the same vtable
14
Member Lookup
• Implementation of a vtable:
– The compiler will generate:
– Consider the code:
foo * f;
f->m();
– Runtime overhead (compared to static binding) – two instructions
15
Member Lookup
• When defining a derived class:
– Ordering is essential:
» all new members introduced by bar must appear at the end:
» additional data members (w) at the end of the record
» additional virtual methods (s and t) at the end of the vtable
» virtual methods overridden in bar (such as m) – appear in bar's vtable at the
same place as in foo's vtable
16
Member Lookup
• Allowed operations (same example):
class foo { ... };
class bar : public foo { ... };
...
foo F;
bar B;
foo * q;
bar * s;
q = &B;
// ok; references through q will use prefixes of B's data space and vtable
s = &F;
// static semantic error; F lacks the additional data and vtable entries of a bar
17
Type Checking
• C++
foo F;
bar B;
foo * q;
bar * s;
...
q = &B;
s = &F;
class foo { ... };
class bar : public foo { ... };
– Type correctness of the code above – checked statically
s = q;
// still an error
– But it can be done:
s = (bar*) q;
// ok, but risky – programmer must ensure that q
refers to a bar object
– Better solution:
s = dynamic_cast<bar*> (q);
// C++ specific – involves dynamic type check
18
Type Checking
• Java
– allows only the "classic" cast, but with dynamic check
• Eiffel
class foo ...
class bar inherit foo ...
...
f : foo;
b : bar;
...
f := b;
-- always ok
b ?= f;
-- reverse assignment, with dynamic check
– Reverse assignment ?= assigns an object reference into a variable only if
the type at run-time is acceptable
» b gets f if f refers to a bar object at run-time
» otherwise b gets nil
19
Type Checking – Implementation
• Eiffel, Java, C++
– what is needed to perform dynamic checking?
» run-time type descriptor included in the object representation
• Smalltalk
–
–
–
–
variables are untyped references
data members are never public
any assignment is legal
only method invocation ("send a message") is dynamically checked
» implementation – dictionary that maps method names to their code
» run-time – lookup in dictionary to check if method is supported
» if not – dynamic semantic error
– comparison to C++ approach:
» more flexible in Smalltalk
» less efficient – increased run-time cost
» delayed reporting of errors
20
Member Lookup
• Disadvantages of virtual methods:
– run-time cost
– preclude in-line expansion of methods at compile time
» performance decrease for small and frequently called methods
• Potential problem with static lookup:
– fragile base class problem (Java):
» large standard library, evolving over time (adding new features)
» user may have old library and run code designed for new library
» code may use the new features
» static lookup – invalid memory access
» dynamic lookup – better, produce error message ("member not found")
21
Classes as "Closures"
• Classes – can implement a mechanism similar to first-class
subroutines
22
Classes as "Closures"
• Advantage of latter version (with classes):
– can also add data members to class bar (and object my_obj)
– function f can use them
– similarity between:
» data members of an object with a virtual method, AND
» referencing environment of a closure in a language with nested scopes
• Application:
– discrete event simulation
– need to have a subroutine schedule_at that:
» takes as parameters a time value and a function f (to be called at that time)
» function f should have an arbitrary set of parameters
– how do we pass such a function f (with ANY number of parameters)?
» pass a "closure" instead – implemented with classes
23
Classes as "Closures"
• Example - discrete event simulation:
24
Download