Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
6 Data Abstraction Packages and encapsulation. Abstract types. Classes, subclasses, and inheritance. Implementation notes. © 2004, D.A. Watt, University of Glasgow 6-1 Packages A package is a named group of components declared for a common purpose. These components may be types, constants, variables, procedures, etc. 6-2 Example: Ada simple package Package: package Earth is type Continent is ( Africa, Asia, Australia, Europe, N_America, S_America); radius: constant Float := 6.4e3; -- km population: array (Continent) of Natural; end Earth; Bindings produced by this package: { Continent the type Continent = {Africa, Asia, …}, radius the real number 6.4103, population an array variable of type Continent Natural 6-3 } Encapsulation (1) Encapsulation means making some components of a program unit (package, abstract type, or class) private. Several possible levels of privacy: • A component is private if it is visible only inside the program unit. • A component is protected if it is visible only inside the program unit and certain closely-related program units. • A component is public if it is visible to application code outside the program unit. A program unit’s API (application program interface) consists of its public bindings only. 6-4 Encapsulation (2) An Ada package consists of two parts: • Public components are declared in the package specification. • Private components are declared in the package body (or in the private part of the package specification). 6-5 Example: Ada package with encapsulation (1) Package specification: package Trig is public function function sin (x: Float) return Float; function cos (x: Float) return Float; public function end Trig; 6-6 Example: Ada package with encapsulation (2) Package body: package Trig is private constant private function twice_pi: constant Float := 6.2832; function norm (x: Float) return Float is … -- compute x modulo twice_pi function sin (x: Float) return Float is … -- compute the sine of norm(x) function cos (x: Float) return Float is … -- compute the cosine of norm(x) end Trig; 6-7 Example: Ada package with encapsulation (3) This package’s API: { sin function procedure that approximates the sine function, cos function procedure that approximates the cosine function } 6-8 Example: Ada encapsulated variables (1) Package specification: package The_Dictionary is public procedure procedure clear; -- Make the dictionary empty. public procedure procedure add (w: in Word); -- Add w to the dictionary if it is not already there. public function function contains (w: Word) return Boolean; -- Return true if and only if w is in the dictionary. end The_Dictionary; 6-9 Example: Ada encapsulated variables (2) Package body: package body The_Dictionary is private constant private variables cap: constant := 1000; size: Integer := 0; words: array (1 .. cap) of Word; procedure clear is … procedure add (wd: in Word) is … function contains (wd: Word) return Boolean is … end The_Dictionary; access accesssize size and andwords words 6-10 Example: Ada encapsulated variables (3) This package’s API: { clear proper procedure that makes the dictionary empty, add proper procedure that adds a word to the dictionary, contains function procedure that tests whether a word is in the dictionary } Possible application code: use The_Dictionary; … if not contains(current_word) then … add(current_word); end if; illegal! … size := 0; 6-11 Abstract types An abstract type has a private representation but is equipped with public operations. (The operations may be constants and/or procedures.) Some PLs support abstract types directly. Ada supports abstract types by means of packages. The abstract type is declared in the package specification in two stages: • The type declaration is public, but doesn’t define the representation. • The private part contains a full type definition. 6-12 Example: Ada abstract type (1) Package specification: package Dictionaries is private type type Dictionary is limited private; -- A Dictionary value represents a set of words. public procedure procedure clear (d: in out Dictionary); -- Make d empty. public procedure procedure add (d: in out Dictionary; w: in Word); -- Add w to d if it is not already there. public function function contains (d: Dictionary; w: Word) return Boolean; -- Return true if and only if w is in d. 6-13 Example: Ada abstract type (2) Package specification (continued): private private constant full type definition cap: constant Integer := 1000; type Dictionary is record size: Integer; words: array (1 .. cap) of Word; end record; end Dictionaries; 6-14 Example: Ada abstract type (3) Package body: package body Dictionaries is procedure clear (d: in out Dictionary) is … procedure add (d: in out Dictionary; w: in Word) is … function contains (d: Dictionary; w: Word)return Boolean is … end Dictionaries; 6-15 Example: Ada abstract type (4) This package’s API: { Dictionary an abstract type representing a set of words, clear proper procedure that makes a dictionary empty, add proper procedure that adds a word to a dictionary, contains function procedure that tests whether a word is in a dictionary } 6-16 Example: Ada abstract type (5) Possible application code: use Dictionaries; main_dict, user_dict: Dictionary; … if not contains(mainDict, current_word) and not contains(userDict, current_word) then … add(userDict, current_word); end if; … user_dict.size := 0; illegal 6-17 Classes (1) An object is a tuple of variable components (instance variables), equipped with a group of operations that access these variables. A class is a set of similar objects. All objects of a given class have similar instance variables, and are equipped with the same operations. A constructor is an operation that creates and initializes a new object of the class. A method is an operation that inspects and/or updates an existing object of the class. 6-18 Classes (2) A Java class declaration: • declares all instance variables • defines all constructors • defines all methods • specifies whether each of these is private, protected, or public. A Java method call has the form “O.M(…)”: • The expression O determines the target object. • M is the name of the method to be called. • The call executes the method body, with this denoting the target object. 6-19 Example: Java class (1) Class declaration: class Dictionary { private int size; private String[] words; private variables public Dictionary (int capacity) { … } public constructor public void add (String w) { if (! this.contains(w)) this.words[this.size++] = w; } public method public method public boolean contains (String w) { … } } 6-20 Example: Java class (2) Possible application code: Dictionary mainDict = new Dictionary(10000); Dictionary userDict = new Dictionary(1000); … if (! mainDict.contains(currentWord) && ! userDict.contains(currentWord)) { … userDict.add(currentWord); } target object … userDict.size = 0; illegal! 6-21 Subclasses Recall: A class C is a set of similar objects. All objects of class C have similar instance variables, and are equipped with the same operations. A subclass of C, S, is a set of objects that are similar to one another but richer than the objects of class C: • An object of class S has all the instance variables of an object of class C, but may have extra instance variables. • Likewise, an object of class S is equipped with all the methods of class C, but may be equipped with extra methods. If S is a subclass of C, we say that C is a superclass of S. 6-22 Inheritance A subclass is said to inherit its superclass’s instance variables and methods. Alternatively, a subclass may override some of its superclass’s methods, by providing more specialized versions of these methods. 6-23 Example: Java class and subclass (1) Class declaration: class Point { protected double x, y; public Point () { x = 0.0; y = 0.0; } public double distance () { return Math.sqrt(x*x + y*y); } method (1) public final void move (double dx, double dy) This method may { x += dx; y += dy; } not be overridden. method (2) public void draw () { … } // draw this point on the screen method (3) } 6-24 Example: Java class and subclasses (2) Subclass declaration: class Circle extends Point { private double r; public Circle (double radius) { x = 0.0; y = 0.0; r = radius; } method (4) public void draw () { … } // draw this circle on the screen method (5) public double diameter () { return 2.0*r; } } 6-25 Example: Java class and subclass (3) Possible application code: Point p = new Point(); Circle c = new Circle(10.0); p.move(12.0, 5.0); c.move(3.0, 4.0); … p.distance() … … c.distance() … … c.diameter() … p.draw(); c.draw(); p = c; p.draw(); p is at (0, 0) c is centred at (0, 0) now p is at (12, 5) now c is centred at (3, 4) yields 13 yields 5 yields 10 draws a point at (12, 5) draws a circle centred at (3, 4) ditto! (dynamic dispatch) 6-26 Example: Java class and subclasses (4) Another subclass declaration: class Rectangle extends Point { private double w, h; public Rectangle (…) { … } method (6) public void draw () { … } // draw this rectangle on the screen method (7) public double width () { return w; } method (8) public double height () { return h; } } 6-27 Overriding Each method of a class C is inherited by the subclass S, unless it is overridden by S. The overriding method in class S has the same name and type as the original method in class C. Some OO PLs allow programmers to specify whether a method may be overridden or not: • In C++, a method specified as virtual may be overridden. • In Java, a method specified as final may not be overridden. 6-28 Dynamic dispatch If methods are overridden, and if the PL allows a variable of a particular class to refer to an object of a subclass, then method calls entail dynamic dispatch. Consider the Java method call “O.M(E1, …, En)”: • The compiler infers the type of O, say class C. • The compiler checks that class C is equipped with a method named M, of the appropriate type. • Nevertheless, it might turn out (at run-time) that the target object is actually of class S, a subclass of C. • If method M is overridden by any subclass of C, a run-time tag test is needed to determine the actual class of the target object, and hence which of the methods named M is to be called. 6-29 Single inheritance Single inheritance allows each class to have at most one superclass. Single inheritance gives rise to a hierarchy of classes. Single inheritance is supported by most OO PLs, including Java and Ada95. 6-30 Example: Java single inheritance Declared classes: Object clone equals … • Date (subclass of Object) • Point (subclass of Object) • Circle, Rectangle (both subclasses of Point). Hierarchy of classes: Point x, y distance move draw Circle r draw diameter Rectangle w, h draw width height Date y, m, d … 6-31 Multiple inheritance Multiple inheritance allows each class to have any number of superclasses. Multiple inheritance gives rise to both conceptual and implementation problems. Multiple inheritance is supported by C++. 6-32 Example: multiple inheritance (1) Declared classes: • Animal • Mammal, Flier, Bird (all subclasses of Animal) • Cat (subclass of Mammal) • Bat (subclass of Mammal and Flier) Mammal • etc. gestation … Class relationships: … … Cat Bat sonar … Animal weight speed … Flier wing-span … Bird egg-size … Eagle … … Penguin … … 6-33 Example: multiple inheritance (2) Suppose: • the Animal class defines a method named move • the Mammal and Flier classes both override that method. Then which method does the Bat class inherit? E.g.: Bat b; b.move(…); Which method does this call? Possible answers: • Call the Mammal method (since Mammal is the first-named superclass of Bat). • Force the programmer to choose, either in the Bat class declaration or in the method call. • Prohibit this method call (since it is ambiguous). 6-34 Representation of objects (1) Each object of a given class is represented by a tag field juxtaposed with the object’s instance variables. The tag field indicates the object’s class. Tag fields are needed whenever objects of different classes can be used interchangeably, in particular to implement dynamic dispatch. 6-35 Representation of objects (2) Implementation of access to an instance variable: • Let o be an object of class C. • Each instance variable o.v has a fixed offset (determined by the compiler) relative to the base address of o. Assuming single inheritance, this implementation works even if o is replaced by an object of a subclass of C (since inherited instance variables are located at the same offset in both C and its subclasses). But multiple inheritance makes it more difficult to represent objects such that instance variables can be accessed efficiently. 6-36 Example: representation of Java objects (1) Representation of Point, Circle, Rectangle objects (simplified): Point tag Circle tag Rect. tag 1.0 x 0.0 x 1.5 x 2.0 y 0.0 y 2.0 y 5.0 r 3.0 w 4.0 h The class tags are actually pointers to “class objects” (see later). 6-37 Implementation of method calls (1) In a method call, the target object’s address is passed to the method, along with the ordinary arguments. (Thus the method can inspect/update the target object.) If the named method is never overridden, the method call is implemented like an ordinary procedure call. Otherwise dynamic dispatch must be implemented, as follows. For each class C in the program, create a class object containing the addresses of C’s methods. Make each object of class C contain (in its tag field) a pointer to C’s class object. 6-38 Implementation of method calls (2) Implement the method call “O.M(…)” as follows: 1. Determine the target object from O. 2. Follow the pointer from the target object’s tag field to the corresponding class object. 3. Select the method named M in the class object. 4. Call that method, passing the target object’s address along with the ordinary arguments. The method named M can be selected efficiently in step 3, since the compiler can determine its offset relative to the base of the class object, assuming single inheritance. Multiple inheritance makes it more difficult to implement dynamic dispatch efficiently. 6-39 Example: representation of Java objects (2) Representation of Point, Circle, Rectangle objects: Point class object tag tag tag 1.0 x 0.0 x 1.5 x 2.0 y 0.0 y 2.0 y 5.0 r 3.0 w 4.0 h method (1) distance method (1) distance method (1) distance method (2) move method (2) move method (2) move method (3) draw method (4) draw method (6) draw method (5) diameter method (7) width Circle class object Rectangle class object 6-40 method (8) height