\c{
Object oriented languages offer a variety of constructs
that may be used to implement a system.
In particular, when developing a class, the
designer has the choice between developing
the class anew, deriving the class using inheritance,
incorporating an (object of an) existing class
to which messages may be delegated,
or instantiating a given template class
with an appropriate type parameter.
The choice may be difficult, since there
are a number of trade-offs involved.
For instance, when using explicit delegation
instead of inheritance, each indirection must
be explicitly coded.
When using inheritance,
derived code can immediately be used,
but the interface of the derived class may get too fat.
The actual choice made will often be dependent on
the functionality offered by the class libraries
available.
For example, only few of the C++ libraries
employ templates. See section [11-lib].
In the absence of template classes, the designer
may be forced to use inheritance and type insecure
casts to mimic generic data types such as lists.
In [HOB87] guidelines are given telling how and when to
use inheritance.
Their view is in accord with a design methodology
centered around subtyping,
that is the derivation of new object types
within the constraints of behavioral conformance.
See slide [3-design-methodology].
}
\slide{3-design-methodology}{Design methodology}{
Subtyping (design methodology)
- stepwise refinement by specialization
{\footnotesize C.f. decomposition : (data/procedural abstraction)}
\nl
}
Specialization -- conceptual hierarchies\n
Implementation -- to realize a supertype\n
Combination -- multiple inheritance
Nonstandard subtyping:\n
Generalization -- \n
Variance -- {\it Mouse Tablet} [Pointing]\n
Limitation -- {\it Deque Stack }
\nln
{\footnotesize {\bf } Creativity and clear headed thinking are the most important ingredients of design } !
\n
}
}
\c{
As we have seen previously, subtyping may be
used to realize a partially defined (abstract) type,
or as a means to add a specialization to a conceptual
hierarchy.
Another valid use of inheritance, involving multiple inheritance,
is for the definition of a type combining the properties
of multiple types, as for instance in the definition
of an assistant derived from a teacher and student class.
In a number of occasions, however, the need may arise
to employ what in [HOB87]
is called non-standard subtyping,
and is also known as non-strict inheritance.
An example of non-strict inheritance is a derivation
that results in a generalization,
as for instance occurs when deriving a colored window
class from a base class window (supporting only
black and white).
We speak of a generalization since the type associated
with colored windows properly encompasses the collection
of black and white windows.
Yet, from an implementation perspective, it may be convenient
to simply extend the code written for black and
white windows, instead of redesigning the class hierarchy.
Another example of non-strict inheritance is
when the derivation results in what may be called
a variant type, which occurs for instance
when deriving a pen or tablet class
from a class defining the behavior of a mouse.
The proper course of action in such cases is to
introduce an abstract class pointing device
from which both the mouse and tablet
class may be derived (as proper subtypes).
Another, equally evident, violation of the subtyping
regime occurs when restricting a given class
to achieve the functionality belonging to the type of
the derived class.
A violation, since the requirement of behavioral
conformance demands that either new behavior is added
or already existing behavior is refined.
Actual limitation of behavior results in a behaviorally
incompatible class.
The standard example of limitation, originally given in [Snyder86]
is the restriction of a double ended queue into
a stack.
A better, and from a type perspective perfectly legal
solution is to derive a stack from a double ended queue
by using private inheritance.
However, from a design perspective, the use of
private inheritance must be considered ill practice,
since dependencies may be introduced in the object model
that remain invisible in a more abstract (type oriented)
description of the system.
Delegation, as in the handler/body idiom described
in section [2-handler], is to be preferred
in such cases since it makes the uses
relation explicit and does not compromise the type
system.
}