Instructor's Guide
intro
polymorphism
idioms
patterns
events
summary,
Q/A,
literature
The multitude of constructs available in C++ to support
object-oriented programming may lead the reader to think
that object-oriented programming is not at all meant
to reduce the complexity of programming but rather to increase it,
for the joy of programming so to speak.
This impression is partly justified, since the number and complexity
of constructs is at first sight indeed slightly bewildering.
However, it is necessary to realize that each of the constructs introduced
(classes, constructors and destructors, protection mechanisms,
type conversion, overloading, virtual functions and dynamic binding)
may in some way be essential to support object-oriented programming
in a type-safe,
and yet convenient, way.
Having studied the mechanisms, the next step is to find proper ways,
recipes as it were, to use these mechanisms.
What we need, in the terminology of [Coplien92], are idioms,
that is established ways of solving particular problems with
the mechanisms we have available.
In his excellent book, Coplien discusses
a number of advanced C++ idioms
for a variety of problem domains,
including signal processing and symbolic computing.
In this section, we will look at the concrete class idiom for C++,
which states the ingredients that every class must have
to behave as if it were a built-in type.
Other idioms, in particular an improved version of
the handle/body or envelope/letter idiom
that may be used to separate interface from implementation,
will be treated in the next section.
Concrete data types in C++
A concrete data type is the realization of an abstract
data type.
When a concrete data type is correctly implemented
it must satisfy the requirements imposed
by the definition of the abstract data type it
realizes.
These requirements specify what operations are
defined for that type, and also
their effects.
In principle, these requirements may be formally
specified, but in practice just an informal
description is usually given.
Apart from the demands imposed by a more abstract
view of the functionality of the type, a programmer
usually also wishes to meet other requirements,
such as speed, efficiency in terms of storage
and error conditions, to prevent the removal of an item
from an empty stack, for example.
The latter requirements may be characterized
as requirements imposed by implementation concerns,
whereas the former generally result
from design considerations.
Canonical class in C++
- default constructor
- copy constructor
- destructor
- assignment
- operators
Abstract data types must be indistinguishable
from built-in types
slide: Canonical class
To verify whether a concrete data type meets
the requirements imposed by the specification of
the abstract data type is quite straightforward,
although not always easy.
However, the task of verifying whether a
concrete data type is optimally implemented
is rather less well defined.
To arrive at an optimal implementation may involve
a lot of skill and ingenuity, and in general
it is hard to decide whether the right choices have been
made.
Establishing trade-offs and making choices,
for better or worse, is a matter of experience,
and crucially depends upon the skill in handling
the tools and mechanisms available.
When defining concrete data types, the list of
requirements defining the canonical class idiom
given in
slide [2-canonical]
may be used as a check list to determine whether all
the necessary features of a class have been defined.
Ultimately, the programmer should strive
to realize abstract data types in such a way
that their behavior is in some sense
indistinguishable from the behavior of the built-in data types.
Since this may involve a lot of work, this need not be a primary aim in the first
stages of a software development project.
But for class libraries to work properly, it is simply essential.