Date post: | 15-Aug-2015 |
Category: |
Technology |
Upload: | adair-dingle |
View: | 162 times |
Download: | 0 times |
Copyright@2014 Taylor & Francis Adair Dingle All Rights Reserved
Object-‐Oriented Design
Inheritance vs.
Delega@on
Inheritance for Polymorphism: Behavioral Reuse
Design Ques@ons
• How to streamline class design for dynamic behavior?
• What is the importance of an interface?
• How to dis@nguish between reuse mo@ves?
Copyright@2015 Adair Dingle
Key Observa@ons
• Inheritance and delega@on BOTH may provide polymorphism
• Type dependencies may be external or internal
• Differing needs for control may drive design
Copyright@2015 Adair Dingle
Chapter 7: Behavioral Design Invoca@on of Func@onality run-‐&me variability vs. compile-‐&me efficiency
• Polymorphism • Sta@c vs. Dynamic Binding • Languages Difference • Design Principles
Copyright@2014 Taylor & Francis Adair Dingle All Rights Reserved
Three Forms of Polymorphism • Overloading aka Ad Hoc Polymorphism
– Allows mul@ple func@on defini@ons with same name – compiler uses parameter type(s) to resolve func@on calls
• Generics aka Parametric Polymorphism – Supports ‘typeless’ defini@on of a class or a func@on – applica@on programmer can later supply type – Compiler generates version of generic class (or func@on) with that
type.
• SubTyping aka Inclusion – describes design of class hierarchy where descendant classes
(re)define, augment, or modify inherited func@onality – Descendant classes are dependent on the base class interface – Dynamic binding expected
Copyright@2014 Taylor & Francis Adair Dingle All Rights Reserved
Example 7.1 Overloaded Func@ons: Moderately Altered Func@onality
void reset() { for (int k=0; k < size; k++)
A[k] = 0.0;
}
void reset(double value) { for (int k=0; k < size; k++)
A[k] = value;
}
void reset(bool op, int factor) { if (op)
for (int k=0; k < size; k++) A[k]*= factor;
else
for (int k=0; k < size; k++) A[k] += factor;
}
Copyright@2014 Taylor & Francis Adair Dingle All Rights Reserved
Example 7.2 Overloaded Func@ons: Consistent Behavior => Generic Func@on
void swap(int& x, int& y) { int hold = x;
x = y; y = hold;
}
void swap(float& x, float& y) { float hold = x;
x = y; y = hold;
}
template <typename someType> void swap(someType& x, someType& y) { someType hold = x;
x = y; y = hold;
}
Copyright@2014 Taylor & Francis Adair Dingle All Rights Reserved
Third Form of Polymorphism • Overloading
– Allows mul@ple func@on defini@ons with same name
• Generics – ‘typeless’ defini@on of a class or a func@on
• SubTyping depends on dynamic binding – Associate func@on call resolu@on with subtype – POSTPONE func@on call resolu@on un@l run-‐@me
Copyright@2014 Taylor & Francis Adair Dingle All Rights Reserved
Sta@c vs. Dynamic Binding
• Sta@c binding – compiler resolves func@on calls – translates each func@on invoca@on into a direct jump – efficient but rigid
• Dynamic binding – compiler does not resolve a func@on call at compile-‐@me. – extra instruc@ons generated – at run-‐@me, func@on address extracted from a jump table – flexible but costly
Copyright@2014 Taylor & Francis Adair Dingle All Rights Reserved
Sta@c vs. Dynamic Binding
Sta@c binding translates func@on calls directly into jump statements
⇒ func@on invoked at the point of call CANNOT vary ⇒ No run-‐@me overhead ⇒ No run-‐@me flexibility
Dynamic binding postpones func@on call resolu@on un@l run-‐@me
⇒ func@on invoked at the point of call CAN vary ⇒ great flexibility ⇒ Run-‐@me overhead ⇒ supports polymorphism and heterogeneous collec@ons
Copyright@2014 Taylor & Francis Adair Dingle All Rights Reserved
Binding Design Choices
• Java – NONE: All func@ons dynamically bound (EXPENSIVE!)
• C#/C++ – Sta@c binding by default (efficient!) – Dynamic binding with keyword ‘virtual’
• Sta@c binding – Reasonable when func@on choice will not vary
• Dynamic binding – Reasonable when subtype affects func@on choice – Heterogeneous collec@ons needed
Copyright@2014 Taylor & Francis Adair Dingle All Rights Reserved
Once Virtual Always Virtual
• See sec@on 7.4 • Address of each virtual func@on placed in class vtab
– “vtab” = = virtual func@on table = = jump table
• Descendant class inherits copy of parent’s vtab – Every virtual func@on remains virtual for all descendants – Each virtual func@on with the same name has the same offset in each class vtab
=> Name corresponds to offset with class hierarchy
• Each overridden func@on – causes an address update in corresponding entry of vtab
Copyright@2014 Taylor & Francis Adair Dingle All Rights Reserved
Heterogeneous Collec@on
• Tied to interface of base class in class hierarchy – Available func@onality defined by public func@ons of base class
• Contains assortment of objects – Each object some (sub)type of class hierarchy – No required order or frequency of (sub)types
• Elements of collec@on are actually address holders – References in C# – Pointer in C++
• Dynamic binding – Postpones func@on resolu@on un@l run-‐@me so actual subtype used – Great flexibility and extensibility!!
Copyright@2014 Taylor & Francis Adair Dingle All Rights Reserved
Heterogeneous Collec@on
• Class hierarchy uses virtual func@ons – variant behavior (based on subtype)
• Traversal of heterogeneous collec@on
– Yields streamline execu@on of varying func@onality – Masks subtype construc@on and evalua@on
• Type extensibility supported
Copyright@2014 Taylor & Francis Adair Dingle All Rights Reserved
Table 7.1 Types of Polymorphism
Polymorpism Characteristics Distinguished by Application
Ad Hoc (Overloading)
Different function versions
Function signature (parameter lists)
Constructors often overloaded
Parametric (Generic)
Type-less functions Type placeholder Multiple (typed) versions automatically generated by compiler
Inclusion (Subtype)
Overridden functions
Same function signature Class scope differs
Heterogeneous collections base class interface Dynamic binding
Copyright@2014 Taylor & Francis Adair Dingle All Rights Reserved
Example 7.8 C++ Polymorphic Object Crea@on
// function that evaluates environment, possibly file input
// generates an object of some type from class hierarchy
// => can return address of any object from class hierarchy
// => subtype of object allocated determined at run-time
// BASE pointer can hold address of ANY class hierarchy object // at compile-time:
// return pointer holding address generated at run-time
// cannot ‘guess’ what (sub)type of object allocated
FirstGen* GetObjAddr() { if (condA) return new FirstGen; // base
else if (condB) return new SecondGen; // derived
else if (condC) return new ThirdGen; // derivedII
…
} // ownership of object passed back
Copyright@2014 Taylor & Francis Adair Dingle All Rights Reserved
Example 7.9 C# Polymorphic Object Crea@on
// function that evaluates environment, possibly file input
// generates an object of some type from class hierarchy
// => can return address of any object from class hierarchy
// => subtype of object allocated determined at run-time
// BASE reference can hold address of ANY class hierarchy object // at compile-time:
// return reference (address of object generated at run-time)
// cannot ‘guess’ what (sub)type of object allocated
FirstGen GetObj() { if (condA) return new FirstGen(); // base
else if (condB) return new SecondGen(); // derived
else if (condC) return new ThirdGen(); // derivedII
…
} // ownership of object passed back
Copyright@2014 Taylor & Francis Adair Dingle All Rights Reserved
Example 7.10 C++ Heterogeneous Collec@on
// initialization of heterogeneous collection:subtype hidden // at compile-time, do NOT know type of object generated
FirstGen* bigPtrArray[100];
for (int k = 0; k < 100; k++)
bigPtrArray[k] = GetObjAddr();
// dynamic behavior for (int k = 0; k < 100; k++)
bigPtrArray[k]-> simple();
…
// MEMORY MANAGEMENT: release heap memory before leaving scope // deallocate dynamically allocated objects
for (int k = 0; k < 100; k++)
delete bigPtrArray[k];
Copyright@2014 Taylor & Francis Adair Dingle All Rights Reserved
Example 7.11 C# Heterogeneous Collec@on
// initialization of heterogeneous collection:subtype hidden // at compile-time, do NOT know type of object generated
FirstGen[] bigArray = new FirstGen[100];
for (int k = 0; k < bigArray.Length; k++)
bigArray[k] = GetObj(); // dynamic behavior for (int k = 0; k < bigArray.Length; k++)
bigArray[k]-> simple();
Copyright@2014 Taylor & Francis Adair Dingle All Rights Reserved
Abstract Classes
• An abstract class is an ‘incomplete’ type defini@on • Objects cannot be instan@ated from abstract class
– at least one method remains undefined OR – no public constructors provided
• Abstract classes – define a common interface for a class hierarchy – Typically define virtual func@ons in interface
=> Design interface of heterogeneous collec@on
Copyright@2014 Taylor & Francis Adair Dingle All Rights Reserved
Table 7.3 Abstract Classes Design Intent Implementation Details Effects
Incomplete Type Definition Deferred methods
Not all functions defined Function prototypes serve as placeholders
Cannot instantiate objects Inheritance required
Base class defines uniform interface for class hierarchy
Derived class(es) override or augment behavior
Inheritance anticipated
Polymorphism: Calls through base typed pointer (reference) resolved wrt base interface
Typed pointer or reference holds address of derived object
Heterogeneous collections Varying behavior Extensibility
Generalization of overriding
Derived class(es) define behavior
Derived class remains abstract unless it redefines inherited deferred methods
Copyright@2014 Taylor & Francis Adair Dingle All Rights Reserved
Example 7.12 C++ Abstract Class
class Shape // abstract class: pure virtual methods { public:
virtual void rotate(int) = 0; virtual void draw() = 0; …
};
// inherited methods defined => descendant class not abstract class Circle: public Shape
{ point center; int radius;
public:
Circle(point p, int r):center(p), radius(r) {}
// once virtual, always virtual void rotate(int){}
// for readability tag as virtual virtual void draw();
…
};
Copyright@2014 Taylor & Francis Adair Dingle All Rights Reserved
Example 7.13 Cannot Instan@ate Abstract Class
Shape s; // cannot instantiate from abstract class Shape* sptr; // can hold address of derived objects
// abstract Shape and derived subtypes Circle, Square, …
// initialize array of Shape pointers
// each pointer can contain address of different subtype
// input function GetObject() constructs some Shape subtype
// on heap and return its address
int main()
{ Shape* composite[100];
for (int i=0; i<100; i++)
composite[i] = GetObjectAddr();
…
// what is drawn?
for (int i=0; i<100; i++)
composite[i]->draw();
}
Copyright@2014 Taylor & Francis Adair Dingle All Rights Reserved
Example 7.14 C# Abstract Class
// abstract easily noted with keyword
abstract class Shape
{ public virtual void rotate(int); public virtual void draw(); …
}
// see section 7.6 for real-world example
Copyright@2014 Taylor & Francis Adair Dingle All Rights Reserved
Tracking (sub)Type
• Compiler effec@vely tracks type • Modern OO constructs increase abstrac@on
– inheritance – virtual func@ons
• Applica@on programmer need not track (sub)type – NO ‘manual’ type checking
• Type checking in code (‘manual’) – tedious and error-‐prone – poten@ally expensive – non-‐extensible approach.
Copyright@2014 Taylor & Francis Adair Dingle All Rights Reserved
Example 7.18 Type Extrac@on in C++
class Base { public:
virtual void surprise();
// process() NOT virtual => statically bound call // => even if overridden, always yields Base functionality void process();
};
// APPLICATION CODE: heterogeneous collections
// virtual function surprise() == automatic type checking
// non-virtual function process() == no type checking // => manual type-checking if Derived behavior desired // when function is not virtual in the Base class
Copyright@2014 Taylor & Francis
Adair Dingle All Rights Reserved
Example 7.18 Type Extrac@on con@nued
// process() non-virtual => forced type checking: dynamic_cast // run-time type check of object whose address held in pointer
// pointer value returned if type matches
// zero if cast fails
for (int i=0; i<100; i++)
{ // elegant: compiler sets up dynamic invocation HeteroDB[i]->surprise();
// clunky, tedious, not extensible if (Child1* ptr = dynamic_cast<Child1*> (HeteroDB[i]))
ptr->process();
else if (Child2* ptr = dynamic_cast<Child2*> (HeteroDB[i]))
ptr->process();
else if (Child3* ptr = dynamic_cast<Child3*> (HeteroDB[i]))
ptr->process();
… // for all relevant subtype variants, test cast else … // catchall: process unmatched subtype
}
Copyright@2014 Taylor & Francis Adair Dingle All Rights Reserved
Example 7.19 Type Extrac@on in C# // same setup: Base class with virtual surprise() & non-virtual process() for (int i=0; i<100; i++)
{ // elegant: compiler sets up dynamic invocation
HeteroDB[i].surprise();
// clunky, tedious, not extensible if (HeteroDB[i] is Child1)
{ Child1 x = HeteroDB[i] as Child1);
x.process();
}
else if (HeteroDB[i] is Child2)
{ Child2 x = HeteroDB[i] as Child2);
x.process();
}
else if (HeteroDB[i] is Child3)
{ Child3 x = HeteroDB[i] as Child3);
x.process();
}
… // for all relevant subtype variants, test cast else … // catchall: process unmatched subtype
}
Copyright@2014 Taylor & Francis Adair Dingle All Rights Reserved
Example 7.20 Type Reclama@on in C++
// virtual whoami() in class hierarchy yields identifying int // myObj is base class pointer, just like HeteroDB[i]
int typeId myObj->whoami(); switch typeId: { case 0: SubType0 ptr = static_cast<SubType0*> (myObj);
ptr->process();
break;
case 1: SubType1 ptr = static_cast<SubType1*> (myObj);
ptr->process();
break;
…
case 8: SubType8 ptr = static_cast<SubType8*> (myObj);
ptr->process();
}
Copyright@2014 Taylor & Francis
Adair Dingle All Rights Reserved
Type Extensibility
• Design of an inheritance hierarchy may be expanded • Addi@onal descendant classes easily defined • What’s needed?
– an appropriately designed base class interface – proper use of polymorphism
⇒ new descendant classes added without breaking client code
⇒ Sotware maintainability (evolu@on supported)
Copyright@2014 Taylor & Francis Adair Dingle All Rights Reserved
Polymorphism and Maintainability
• Overloading aka Ad Hoc Polymorphism – should make code more readable – can isolate func@onal varia@ons based on parameter type
• Generics aka Parametric Polymorphism – promotes code reuse and familiarity – standard classes and func@ons
• SubTyping aka Inclusion – supports type extensibility – applica@on code does not break when new subtype added to class hierarchy.
Copyright@2014 Taylor & Francis Adair Dingle All Rights Reserved
Table 7.10 Func@on Name Reuse Overloaded Overridden Virtual
Same name Number, order, type of parameters varies
Same name Same signature Same class hierarchy
Same name Same signature Same class hierarchy
Function signature Parameters drive selection
May or may not be dynamically bound (C#,C++)
Dynamic Binding function call resolved at run-time
Offers choice based on parameters
Redefines inherited functionality
May be overridden in derived class(es)
Constructors often overloaded
Return type not part of signature
Requires vtab Type of this pointer not known until run-time
Distinct functions Masks parent method Overhead of indirect call
Overloaded for variety May NOP inherited method
Prevents inlining functions
Overloaded for type ð generics
Extensible
Copyright@2014 Taylor & Francis Adair Dingle All Rights Reserved
Open Closed Principle A class should be open for extension and closed for modifica&on • Emphasis on Sotware maintainability • Polymorphism: Common Interface in Base Class
– base type defines key func@onality – defers complete implementa@on to descendant classes, OR – variant behavior among within a heterogeneous collec@on
• As sotware evolves – base class should be stable (closed to modifica@on) – design of addi@onal descendants expected (open for extension).
Copyright@2014 Taylor & Francis Adair Dingle All Rights Reserved
Liskov Subs@tu@on Principle
Given a type T with a subtype S defined via inheritance, any object of subtype S can serve in place of an object of type T
• Strong support of is-‐a rela@onship • Any descendant can stand in for parent object • Implies the power of heterogeneous collec@ons
• Great variability achievable in stable sotware systems • Type extensibility and sotware maintainability
Copyright@2014 Taylor & Francis Adair Dingle All Rights Reserved