250 likes | 807 Views
Dynamic Binding (Section 10.4) CSCI 431 Programming Languages Fall 2003 A compilation of material developed by Felix Hernandez-Campos and Mircea Nicolescu Fundamental Concepts in OOP Encapsulation Data Abstraction Information hiding The notion of class and object Inheritance
E N D
Dynamic Binding(Section 10.4) CSCI 431 Programming Languages Fall 2003 A compilation of material developed by Felix Hernandez-Campos and Mircea Nicolescu
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
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
InheritanceNotation Base Class (or Parent Class or Superclass) Java.awt.Dialog Is-a relationship Derived Class (or Child Class or Subclass) Java.awt.FileDialog
Example (C++): class person { ... }; class student : public person { ... }; class professor : public person { ... }; student s; professor p; ... person * x = &s; person * y = &p; 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 // Both student and professor objects have all properties of // a person object // Both can be used in a person context
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 () 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 (); // ?? Dynamic Method Binding
Example (C++): student s; professor p; ... person * x = &s; person * y = &p; x->print_mailing_label (); // ?? y->print_mailing_label (); // ?? • 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 Dynamic Method Binding • Two alternatives for choosing the method to call: • 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)
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 Dynamic Method Binding • Simula, C++, Ada 95 • static method binding by default • how do we specify dynamic binding in C++? • label individual methods as virtual
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 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 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 Virtual and Non-Virtual Methods
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 Abstract Classes
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 Member Lookup
Implementation of a vtable: • Consider the code: foo * f; f->m(); • Runtime overhead (compared to static binding) – two instructions Member Lookup • The compiler will generate:
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 Member Lookup
Allowed operations (same example): class foo { ... }; class bar : public foo { ... }; ... foo F; bar B; foo * q; bar * s; q = &B; // s = &F; // Member Lookup ok; references through q will use prefixes of B's data space and vtable static semantic error; F lacks the additional data and vtable entries of a bar
C++ class foo { ... }; class bar : public foo { ... }; foo F; bar B; foo * q; bar * s; ... q = &B; s = &F; • Type correctness of the code above – checked statically s = q; // • But it can be done: s = (bar*) q; // • Better solution: s = dynamic_cast<bar*> (q); // Type Checking still an error ok, but risky – programmer must ensure that q refers to a bar object C++ specific – involves dynamic type check
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 Type Checking
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 Type Checking – Implementation
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")
Classes – can implement a mechanism similar to first-class subroutines 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 Classes as "Closures"
Example - discrete event simulation: Classes as "Closures"