C++ and OOP Tips
What follows are some useful tips that apply to C++ and OOP.
- Put documentation for a class in the header file for the class.
Most users of a class never read the code for the class; the interface
should be sufficient.
Comments within the header file should provide any details needed
for users of the class, including comments about the efficiency
of the operations provided by the class.
- Don't embed application-specific code within generic data
structures. There should be no indication within the definition
of a data structure like a dictionary as to what application is
using the structure. Similarly, don't embed representation-specific
code for a data structure outside the class definition for the
structure. Abiding by these rules maintains the relative independence
of the data structure code and the applications that use it.
- If you define a destructor for a class, be sure
the destructor destroys all of the space
associated with the class.
In particular, if you define a destructor for an open hash table,
the destructor should reclaim both the space for buckets,
and the space for linked entries.
- Avoid passing large data objects as value parameters.
C++ makes it easy to treat complex data structures the same
as integers, but it is easier to copy an integer than to copy a tree.
Note that when you pass an object by value,
the constructor for the class will be called to
create the copy for the procedure, and a destructor will be
called at the end of the procedure.
- Design the external interface so that common operations on
the class only require a single function call.
Such an interface ensures
that users aren't required to perform multiple operations at once.
For example, you might combine the lookup and insert operations on
a dictionary into a single operation that returns the item
if found, and otherwise inserts it in the dictionary.
Note that in combining these two operations into one, we only
have to lookup the address of the item in the dictionary once.
- Always supply a return type for functions.
If the function doesn't return a value, then the return
type is "void".
- Include an "iterator" in the interface of most data structures.
Iterators are operations that return the elements of a data structure
one at a time. The first call to an iterator returns the first
element in the structure; subsequent calls return the "next" element.
Iterators can be used to debug an implementation (by printing out
all the elements in the structure), and are often used for any
operation that must access every element in the structure.
- Avoid embedding a specific base type in generic data structures.
For example, rather than define a dictionary that holds strings
(and therefore can't include counters for the number of occurrences
of the string), define a dictionary that holds items of some base type.
Define the base type to include strings, and any counters you need.
In this way, you can augment the base type without changing the
dictionary class.