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	
  

Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

  • 1.
    Copyright@2014                Taylor  &  Francis               Adair  Dingle      All  Rights  Reserved   Object-­‐Oriented  Design     Inheritance     vs.     Delega@on          Inheritance for Polymorphism: Behavioral Reuse
  • 2.
    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  
  • 3.
    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  
  • 4.
    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  
  • 5.
    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  
  • 6.
    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  
  • 7.
    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  
  • 8.
    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  
  • 9.
    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  
  • 10.
    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  
  • 11.
    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  
  • 12.
    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  
  • 13.
    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  
  • 14.
    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  
  • 15.
    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  
  • 16.
    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  
  • 17.
    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  
  • 18.
    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  
  • 19.
    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  
  • 20.
    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  
  • 21.
    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  
  • 22.
    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  
  • 23.
    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  
  • 24.
    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  
  • 25.
    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  
  • 26.
    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  
  • 27.
    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  
  • 28.
    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  
  • 29.
    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  
  • 30.
    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  
  • 31.
    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  
  • 32.
    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  
  • 33.
    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  
  • 34.
    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