420 likes | 733 Views
Inheritance. Reusability ; Extendibility ; Type Safety (Minimize Repetition , Accommodate Variation in a Reliable way). Example : Rectangle is a Polygon . Polygon ( (Direct) Ancestor ) Methods : translate, rotate, perimeter, etc
E N D
Inheritance Reusability ; Extendibility ; Type Safety(Minimize Repetition, Accommodate Variation in a Reliable way) L112Inh
Example : Rectangle is a Polygon. • Polygon ( (Direct) Ancestor ) • Methods: translate, rotate, perimeter, etc • Fields: listOfVertices, etc • Rectangle inherits from Polygon. • Methods: translate, rotate, etc • Fields: listOfVertices, etc • Rectangle ( (Direct) Descendant ) • Changes Method (for Efficiency only): perimeter • Adds Field: diagonal L112Inh
Invariant Inheritance Rule • The invariant of a class applies to all its descendants. That is, the class invariant of all ancestors applies to a class. • Constructors • A constructor establishes the class invariant. • So, a parent’s constructor cannot serve as the child’s constructor, in general. That is, constructors are not inherited as constructors. • However, a parent’s constructor is accessible in the child class. L112Inh
Example: OrderedList is a List. • List • Methods: empty(), isEmpty(), insert(_), head(), tail(). • OrderedList • New constructor: order(List) • “Inherited” Methods : empty(), isEmpty(), insert(_),head(), tail() • Modified Semantics • head() : Returns the smallest element, • tail() : Deletes all occurrences of the smallest element. L112Inh
Implementations • Invariant 1 ->The array representation is sorted in the non-decreasing order. • Code shared : empty(), isEmpty(), head() • Redefined : tail(), insert(_) • Invariant 2 ->true • Code shared : empty(), isEmpty(), insert(_) • Redefined : head(), tail() L112Inh
Behavioral specification ADT OrderedList is not a subtype of ADT List. • List: length(tail(L)) + 1 = length(L) • OrderedList: length(tail(L)) + 1 <= length(L) • Implementation • Class OrderedList is a subclass of class List. • Code sharing. • Notion of Substituitivity • Java uses message signatures. • Eiffel encourages behavioral view. L112Inh
List li = new List(); li.insert(5); li.insert(5); li.insert(5); li.tail(); li.tail(); // assert: // ! li.isEmpty() List li = new OrderedList(); li.insert(5); li.insert(5); li.insert(5); li.tail(); li.tail(); // exception: // NullPointer OrderedList is not a subtype of List. L112Inh
Polygon p; Rectangle r; Triangle t; p := r; p := t; r := p; Polymorphic entity (reference type) Descendants Polymorphic assignment type of rhs conforms to type of lhs Illegal assignment Polymorphism L112Inh
p t Polymorphic Assignmentp := t; 1. No transmutation of an object. 2. No change in (run-time) type of the object. 3. No change in (compile-time) type of the entities. 4. Only reference reattachment. 5. Class (type) of t is a descendant of class(type) of p. L112Inh
Typing for Inheritance • Goal • Guarantee at compile-time that no incorrect run-time type combination can occur. • Feature Call rule • In x.f, where type of x is based on C, feature f must be defined in one of the ancestors of C. • legal : p.rotate(), r.rotate(), p.perimeter(), r.perimeter(), etc • illegal: p.diagonal L112Inh
Conformance A type Uconforms to type Tif and only if the class of U is a descendant of the class of T. • Type Conformance Rule An attachment of target x and source y (in an assignment x := y; or in the use of y as an actual argument to a routine call where x is the formal argument) is only valid if the type of y conforms to the type of x. • Illegal: t := r; p := t; t:= p; • Illegal: p:= r; p.diagonal; L112Inh
Static and Dynamic Type • Dynamic type • An object only has a dynamic type that never changes during the object’s lifetime. (RTTI) • At any time during the execution, a reference/entity has a dynamic type which is the type of the object it is attached to. • Static type • Only an entity has a static type, the type with which it was declared. L112Inh
Static-dynamic type consistency • An entity declared of type T may at run-time only become attached to instances of class T. • Instances of class T include direct instances of class T and instances of the descendants of class T. L112Inh
P • Statically typed language (E.g., Ada) static-type(entity) = dynamic-type(object) • All type checking done at compile-time • Efficient but inflexible. • OOPL Cases: Java’s primitive types, Eiffel’s expanded types, etc. • Dynamically typed language (E.g., Scheme) Entity type-less; objects carry type-tags. • All type checking done at run-time (inefficient). • Flexible but inefficient. • OOPL E.g.: Smalltalk. L112Inh
Strongly typed OOPLs (E.g., Eiffel, Java, C++) dynamic-type(object) conforms to static-type(entity) • Flexible Supports heterogeneous data structures (through dynamic binding) • Reliable Provides compile-time checks to ensure that there are no undetected type violations at run-time. L112Inh
Type Casting : Assignment Attempt p p := r; … ; r := (Rectangle) p; • Applications • External : Testing objects received over the network, or retrieved from persistent storage. • Internal : Manipulating heterogeneous data. • Others : Using general purpose utility classes (e.g.,java.util.Vector) r L112Inh
Dynamic Binding • Operations defined for all polygons need not be implemented identically for all variants. p.perimeter() • Then the dynamic form (type) of the object attached to p determines which version of the operation will apply at run-time. • “Automatic dispatch” minimizes explicit run-time type tests. • Semantics preserving Re-definitions The precondition and postcondition of a routine applies to any redefinition. Furthermore, the original version may be used in the redefinition. L112Inh
Dynamic Binding and Efficiency • Estimated Overhead : 15% - 30% • The overhead of dynamic binding is small: an index computation and an array access. • The overhead is constant for both single inheritance and multiple inheritance. • In non-statically typed languages, this grows with the depth of class hierarchy. • In-lining and static binding can be used to optimize calls in certain situations. L112Inh
C++ Approach : What not to do! • C++ uses static binding as the default. • Inappropriate because it is an optimization only when it has the same semantics as dynamic binding; otherwise, it is an error. • C++ requires programmers to select static or dynamic binding for each method. • Efficiency concerns must be left to the compiler. • This choice goes against Open-Closed principle. • Rule of thumb • Give prominence to correctness over efficiency by declaring all methods virtual. L112Inh
C# Approach • Overriding by using signature match not robust for code evolution class Parent {… } class Child : Parent { public virtual void aMethod(){…} } // illegal in C# class Parent {… public virtual void aMethod(){…} } L112Inh
(cont’d) class Parent {… public virtual void aMethod(){…} } • To override class Child : Parent { public virtual override void aMethod(){…} } • To achieve independence class Child : Parent { public virtual new void aMethod(){…} } L112Inh
The meaning of Inheritance : Q is a P. • Module Extension Facility (Subclass) • Enables Q to Reuse Code from P, modifying/adding methods and fields. • Openness : Customization by clients. • Type Specialization (Subtype) • Substituitivity: An instance of Q is usable in all contexts where an instance of P is expected. • Values : Instances of Q included in instances of P. • Operations: Every operation applicable to a P’s instance is also applicable to a Q’s instance. L112Inh
Quick Recap of Applications of Inheritance • Code Reuse • applicable to reference types and expanded types. class Point { … move(int x, int y) { …}; } class ColoredPoint extends Point { …} { ColoredPoint cp; … cp.move(4,5); … } • Polymorphism • applicable to reference types (no method redefinition). { Point p = new ColoredPoint(); p.move(4,5);} • Polymorphism and Dynamic binding • applicable to reference types with method redefinition. { Polygon p = new Rectangle(4, 5); p.perimeter();} L112Inh
Inter-Class Relationships “ACarOwneris aPerson andhas aCar.” • Composition (Client Relation) (“has a”) • Inheritance (Subclass Relation) (“is a”) class CarOwner extends Person { Car c; ... } • The difficulty in choosing between the two relationsstems from the fact that when the “is” view is legitimate, one can always take the “has” view instead. class CarOwner { Car c; Person p; ... } L112Inh
CarOwner fields CarOwner fields Subclass instance; Client field Person fields Car Car L112Inh
Choosing between Client and Inheritance • If every instance of P initially has a component of type Q, but that component may need to be replaced at run-time by an object of a different type, make P client of Q. • (P has a Q.) (Person has a car.) • If there is a need for entities of type Q to denote objects of type P, or for more polymorphic structures containing objects of type Q of which some may be of type P, make P heir of Q. • (P is a Q.) (CarOwner is a person.) L112Inh
Coupling : Inheritance vs Composition class P extends Q {} • Inheritance exposes a class to the details of its ancestors’ implementation. So, changes to a class usually requires a recompilation of its descendants, and may sometimes even require modification to the subclass code. class P { Q q; ... } • Composition usually requires objects to access their components solely through their interfaces, thereby respecting encapsulation. L112Inh
public Updates class P extends Q {} • A public method in Q is applicable to instances of P. • If a new public method is added to Q, it is automatically available on instances of P. class P { Q q; ... } • The public methods applicable to instances of P are the ones explicitly coded in P (unless q ispublic). • If a new public method is added to Q, it is not automatically available on instances of P ( via p.q) (unless q ispublic). L112Inh
Delegation and Composition • In delegation, two objects are involved in handling a message: the receiver object dispatches (delegates) the message to a component object that implements it. • Delegation is a technique for making composition as powerful for reuse as inheritance. Inheritance can be simulated using delegation by letting the receiver pass a self-reference to the component. • In general, delegation is dynamic and flexible; inheritance is static and efficient. L112Inh
Interface Inheritance • An object/class has type T if it implements (that is, responds to) the set of messages defined in interfaceT. • An object O2 can be substituted for another object O1 if O2 implements the same interface as O1. (Signature-basedSubtyping) • An interface decouples a client from a supplier, facilitating changing of a supplier or reusing a client. (Polymorphism, Dynamic Binding) L112Inh
Software ICs (Brad Cox) Socket (Client) Compatible IC (Supplier) Incompatible IC (Supplier) L112Inh
Standardize interfaces and functions for client/supplier interchangeability. • Syntax • Number of pins, Location of pins, etc • Static Semantics • “Functionality” of pins : Data, Address, Power supply, etc • Dynamic Semantics • Voltage/Current/Power spec., Protocols, etc • “Software Maintenance” • Repair (debugging) • Evolution (new functionality) L112Inh
Example : OOP Style vs Procedural Style • Client • Determine the number of elements in a collection. • Suppliers • Collections : Vector, String, List, Set, Array, etc • Procedual Style • A client is responsible for invoking appropriate supplier function for determining the size. • OOP Style • Suppliers are responsible for conforming to the standard interface required for exporting the size functionality to a client. L112Inh
Client in Scheme (define (size C) (cond ( (vector? C) (vector-length C) ) ( (pair? C) (length C) ) ( (string? C) (string-length C) ) ( else “size not supported”) ) )) (size (vector 1 2 (+ 1 2))) (size ‘(one “two” 3)) L112Inh
Suppliers and Client in Java interface Collection { int size(); } class myVector extends Vector implements Collection { } class myString extends String implements Collection { publicint size() { return length();} } class myArray implements Collection { int[] array; publicint size() {return array.length;} } Collection c = new myVector(); c.size(); L112Inh
Dynamic Binding : Revisited • Decentralized Software Architectures • Classes manage their own implementations and do not meddle in each other’s affairs. (cf. procedural paradigm for dealing with variants.) • Representation Independence • A client may request an operation, and the run-time system automatically finds the appropriate implementation. • Frameworks L112Inh
Specialization (subtype) Square is Rectangle. Specification (interface) Rocket is java.lang.Runnable. Scribble isMouseMotionListener; Combination (multipleinheritance) TA is Teacher, Student. Extension (Generalization) ColoredPoint is Point. Facility Inheritance Component is java.io.Serializable. Point is java.lang.Object. Construction (C++privateinheritance) Set is pvt. List. Color ispvt. Number. Stack is pvt. Vector. (Subclass that is not a Subtype.) Limitation Stack is Deque. BoundedStack is Stack. Forms of Inheritance L112Inh
Access Control in C++ • Keywords: public, protected, private • If a subclass inherits privately, it cannot be considered a subtype of the original class. • Constant Members • Immutable fields, which cannot be assigned. • Friend functions can read/write private and protected fields within an object. L112Inh
Interpretation of private • Statically typed languages such as C++, Java, etc control visibility on the class-level. That is, an instance of a class can access the private fields of another instance of the same class. • Dynamically typed languages such as Smalltalk, etc. control visibility on the object-level. No object can access private fields of another object. L112Inh
Constant Member and Friend Function class E { private: const int i; public: E( int ); int rd( E& e ) { return e.i; } } E::E(int x) : i(x) { } Class-level visibility class Complex { private: double r,i; public: Complex (double a, double b) { r=a; i=b; } Complex operator + (Complex & c) { return Complex ( r + c.r, i + c.i ); } } L112Inh
Access specifiers control access, not “visibility”. int i; class A { private: int i; } class B : public A { void f() {i++;} } Error: A::i is private. Global i invisible in B. Access control does not guarantee security. class Sneaky { private: int safe; public: Sneaky() {safe=10;} int& sorry() {return safe;} } Sneaky x; x.sorry() = 17; L112Inh
To match the message with a method, C++ searches the ancestor classes of an object. The class that defines the message name is further searched to “match” the entire signature. Even if a better match is inheritable, it will not be considered. (Cf. Java) class A { public: void test(double d){} } class B : public A { public: void test(int i) {} } Error: B b; b.test(2.5); Correct: void B::test(double d) { A::test(d); } Interaction between Overloading and Overriding L112Inh