Discussion of General Guidelines Relation to C++
Next: Discussion of Specific
Up: GUIDELINES
Previous: GUIDELINES
The following terms are used in the discussion below.
- Attribute.
-
Attributes hold the state information of an object from a class.
- Declaration.
-
A declaration declares the type of an identifier, but does not allocate storage
for it (e.g., void update(stack s); or
class Stack {...};).
The declaration of a function is often called its prototype.
- Definition.
-
A definition declares the type of an identifier and allocates storage
(e.g., Stack s1, s2; or
int increment(int x) { return x+1; }).
The definition of a function, which contains the body of the function,
allocates storage for the body of the function.
- Method.
-
Methods are the functions (services) provided by the objects of a class.
These definitions are used in the following discussion of the general guidelines.
Section 2.2 discusses the specific guidelines.
Note that the number for each guideline is prefixed by a ``G'' to distinguish
references to guidelines from references to sections of the text.
For example G3.1, refers to Guideline 3.1, while 2.2 refers to Section 2.2.
- G1.2.7 Precision and Accuracy.
-
Regression test the floating point data type to assure compliance with
standards (e.g., the floating point standard ANSI/IEEE Std 754-1985).
For integer types, C++ guarantees only that sizeof(short) <= sizeof(int)
<= sizeof(long);
no guarantee that a particular size has a particular number of bits is made.
Use regression testing to ensure the size of ``short'', ``int,''
and ``long'' are sufficient.
Such testing should be made part of program startup, to protect against
improper porting of the software.
(For additional safety and control, use classes such as SafeInt,
described in example 3.1 in Section 3).
- G1.2.11 Control of Class Library Size.
-
Failure to break the problem down into the correct classes can lead to too few
or too many classes.
Both tend to obscure the relationship between the code and the problem domain
and thus increase the possibility of errors.
In other words, the problem and not some outside guideline should dictate the
number of classes.
- G1.2.12 Minimizing Dynamic Binding.
-
In the SoHaR report [SoH95] this guideline
confuses two unrelated topics: dynamic function binding and dynamic link libraries.
Dynamic binding occurs when a virtual function is called.
The actual function that gets called is determined dynamically at run time.
Dynamic binding poses no more risk than static binding in well constructed classes.
Dynamic link libraries are linked in with an executable at load time rather
than link time.
This produces smaller executables, but uses the library code on the target
system and not that of the development system.
Thus the developer and tester may not uncover problems that arise when a
dynamic link library on a different machine is used.
At a minimum, regression testing of the libraries on both systems should be
performed (see G3.1.1 below).
The use of dynamic link libraries is not recommended in safety critical code.
- G1.2.13 Control of Operator Overloading.
-
Overloading an operator to other than its obvious meaning may lead to errors in
the code.
For example, the operator Complex::operator+ that adds two complex
numbers has the obvious meaning, while the operator List::operator+ that
adds an element to a list does not (this operator is reasonable, but not
obvious).
- G2.1.1 Control of Internal Diversity.
-
To support internal diversity, create multiple classes that respond to the same
messages, but implement the corresponding methods differently.
This allows the classes to be used interchangeably.
These classes should also have different internal data representation
i.e., different attributes.
- G2.3.1 Input Data Checking.
-
Besides checking program input for validity, input data checking includes input
parameter checking.
For a class, this must include the current state of the object receiving
the message.
In this case, each class can include a (private) method responsible for
normalizing its internal state.
This method is called at the beginning of other methods of the class
(see G2.3.2).
- G2.3.2 Output Data Checking.
-
In addition to checking program input for validity, each method could check
its output.
For methods that modify the internal state of an object (especially class
constructors) this includes normalizing the current state of the object.
For example, class polar_point would contain a function
normalize(), which ensures a positive radius and an angle between 0 and
360 degrees.
Checking validity of both input (G2.3.1) and output (G2.3.2) may be redundant.
- G3.1.1 Controlled Use of Built-in Functions.
-
Use regression testing to verify compliance of built-in functions with
standard and expected behavior.
For example, one built-in operator with different behavior on different
systems when applied to negative numbers is integer remainder
(% in C++).
Regression testing could be performed as part of program initialization to
protect against the program being ported to a different machine.
If a separate compliance test program is used, it must be run on both the
development system and the target system if dynamic libraries are used (see
G1.2.12).
A better solution is to code for portability as in the example in
Section 3.1.
- G3.2.1 Controlled Use of Compiled Libraries.
-
Use regression testing to verify compliance of library functions
with standard and expected behavior (see G3.1.1).
Class libraries that provide smart (safe) pointers and array bounds checking
should be used.
- G4.1.1 Conformance to Indentation Guidelines.
-
Consistent code appearance helps reduce oversights made by human code inspectors.
- G4.1.2 Descriptive Identifier Names.
-
Appropriate names help the code be ``self documenting'' which reduces the need
for comments.
Self documenting code also avoids out-of-date comments that fail to reflect
the current code.
The style encouraged in object-oriented programs is to have lots of small
functions [CGZ94];
this provides opportunities for including good internal documentation (see
G4.1.3) through the use of good function names.
- G4.1.3 Comments and Internal Documentation.
-
Minimize the use of comments:
If something can be stated in the language itself, it should be, and not just
mentioned in a comment.
Comments should identify the major data structures and the purpose, inputs,
and output of each function.
Well written code should be self documenting.
Considering that object-oriented programs typically have short single purpose
functions and each function should have a descriptive header comment,
individual line comments may impede rather than help program understanding.
- G4.1.4 Limitations on Subprogram Size.
-
This is encouraged by the object-oriented
programming style.
A well written object-oriented program will naturally have many short functions.
- G4.3.1 Single Purpose Function.
-
Each function should implement a single thought.
As mentioned in G1.2.9, functions should be divided into evaluation functions
and update functions.
No function should do both.
- G4.4.1 Isolation of Alterable Functions.
-
Isolation of alterable functions can be obtained in two ways.
First, placing such functions in subclasses reduces the need to change the
superclass when an alterable function in the subclass must be altered.
For example, consider the class displayable_playing_card, a subclass of
class playing_card.
While playing cards seldom change, display technology does.
However, all the changes for a new display technology should be localized to
attributes and methods in displayable_playing_card.
Those methods and attributes inherited from playing_card should remain
unchanged.
The second alternative is to group alterable functions together in their own
class.
This should be done with alterable functions not directly related to any other
class.
- G4.5.1 Isolation of Non-Standard Constructs.
-
As in G4.4.1, isolate these in separate subclasses or their own class.
Next: Discussion of Specific
Up: GUIDELINES
Previous: GUIDELINES
David Binkley
Thu Feb 29 10:02:46 EST 1996