4.1 Implementing a Class
A good class definition and implementation must have many desireable
properites.
Because a class captures an
abstraction, the
class must have all of the
properties of a good abstraction. But as an executable
representation a class must also have other properites beyond those of
an abstraction.
The three major properties that a class must possess are that it be:
- correct
- an object of the class must maintain its state properly and respond to
invocations of its methods with the expected results. The most
stringent level of correctness is a formal proof, though such proofs
are usually reserved for safety-critical components due to the high
cost of proving correctness of software. More common are less
stringent levels achieved through testing. No amount of testing
establishes the formal correctness of a class. However, useful and
measureable degrees of reliability and dependability can be achieved.
- safe
- when used in obvious ways, an object of a class should not produce
unexpected or harmful consequences. In particular, the class should
behave safely when passed as a parameter or when objects are assigned
to one another. In C++, special constructors for copying and special
actions for assignment can be given.
- efficient
- the object should make efficient use of processor and memory
resources. While the most important means for ensuring efficiency
reside in the overall system design and the choice of critical data
structures and algorithms, the class implementor has several ways of
improving the efficiency of the implementation.
Given the desired properites of abstractions and those of a class, it
is clear that good object-oriented design is a creative and
challenging activity.
The implementor of classes must be a proficient user of basic
tools. In addition to the obvious need for a compiler, is the need for
proficiency in using a symbolic debugger during development and
testing. Any system beyond the most trivial ones also require the use
of tools to (re)build the executable system from its source
code when some part of that code has changed. For trivial systems all
of the code can be recompiled every time any part of it is
changed. With modest and large systems, this brute force approach is
impractical because the time to recompile and relink the system is
execessive. However, it is not practical for the implementor to
remember all of the ways in which parts of the system must be rebuilt
when some parts have changed. Thus, tools must be used to make the
(re)building process efficient and accurate.