Old World Foundry Coding Standards
These guidelines were written in 1995, some of the reasons are no longer relevent.
- .hp : C++ header file
- .hpi : C++ inlines (included by the .hp file)
- .cc : C++ code
- .h : C header file
- .c : C code
Never use multiple inheritance
Flawed in design and implementation
Never use exception handling. Flawed in implementation
Never put inline definitions in the class declaration.
All inlines should go in the .hpi files.
Never overload the following operators:
| * (unary) & (unary) = = , ->* -> () ! &&
Never use a cast where a constructor conversion is occuring.
Use the new style of conversion.
Never pass NULL objects by reference.
For gcc this means that we swhould be able to compile with the -fnonnull-objects flag and preserve the correctness of the program.
Never use a const reference in a class.
This leads to ugly constructors and space inefficiency. Use inline fetch methods instead.
Never use the implicit copy constructors.
Strictly according to C++, if any public constructor is defined for a class T, then the constructor T::T(const T&) is implicitly
defined. To insure that implicit copy constructors are not used inadverntently, each class which does not need such a constructor
should declare a private version (and not implement it) so that using it causes a link error.
Avoid copy constructors in general.
If used, one must explicitly define these whenever needed, which is tedious as well as error prone (since one must always remember
to updaetg the copy constructor when adding data members to a class). Each member should be explicitly copied. Note, however, that this
allows for greater flexibility, such as copying of pointers containing non-shared state. Perhaps automatic verification for copy
constructors could be implemented.
Avoid classes consisting of purely static members (modules).
These may be equivalently rewritten as normal members with a single static instance of the class, thus unifying class styles with more normal classes.
Avoid operator overloading unless it really makes sense, and makes the code more clear.
The only case this should be used for is types which are inherently numeric. Common examples are Scalar, Vector, and Matrix classes, which override
all the integral operators as one would expect for linear algebra.
Avoid using pointers to functions or pointers to members.
There is probably a better way to do it.
Avoid explicit casts.
For example, when refining subclasses, use a virtual translation function instead (so that errors can be detected).
Production versions may conditionally compile to casts where speed is important.
Avoid passing/returning classes.
Use the keyword UNAVOIDABLE in a comment near such code.
Always use an explicit :: to mark the scoping of C++ external functions.
Always use meaningful names for identifiers, especially any identifier which has global scope.
We assue an oimplementation in whcih the first 31 characters are unique and case senstive for internal and external identifiers (note that ANSI only specifies 6 case insensitive
characters for external identifiers, clearly insufficient).
Always use const for input only parameters.
ALso be sure to always label const functions as such. (The simplest way is to assume a const function until proven otherwise.
Usually pass objects by reference rather than pointers.
Unless one explicitly needs the concept of an invalid object (i.e. a NULL pointer), or one explicitly needs the concept of a pointer (e.g. for memory allocation).
Usually use constructors and destructors where it makes sense.
Thus initialization and cleanup are always in a known place. Do not be scared to use dynamic memory allocation, especially for initialization.
We assume that all .cc files have a corresponding .hp .hpi (which may be empty). All externally visible class definitioins go in the .hp file, all inline definitions for such classes go in the .hpi file.The .hp file additionally contains any globally visible #defines, enums and/or typedefs associdated with the classe(es) defined. There will be no restriction about how many classes are defined in a .hp file (and of courfse corresponding .cc files).In the special case of a single class, however, the file name should strongly reflect the class name. In other cases the classes should be tightly releatd, such that inclusion into one interface makes sense. The .hp header includes the .hpi file and the end, usually wrapped with something whic looks like:
#if USE_INLINE_INCLUDES || defined(_ABSTRACT_CC)
#include "abstract.hpi" /* include inline definitions */
This allows explicit compilation for non-inline versions, without relying on particular compiler implementations (which can be very usefull for debugging).
All headers are to be included only once, with the #ifndef/#define as the first thing in the file, followed by the banner, e.g.
/* banner */
We make an explicit mapping from filename to internal identifier as follows (given as a perl script):
tr/A-Za-z/a-zA-Z/; # invert case for letters
s/[^A-Za-z0-9/_/g; # anything weird (e.g. '.') becomes a _
s/^/_/; # prepend an underscore
An alternative would be to simply go to uppercase, but this convention is attractive because it does not lose any information if filenames are restricted to letters, numbers, and '.'. Because of the DOS problem, file names should be 8 characters or less and only lower case (thus creating a simple translation from DOS to other).
Because we only conditionally include the inline definitions, we insist that instead of the keyword inline we use INLINE which may be conditionaly compiled to nothing for the case where we do not compile using inline functions. Also note that the .cc file expects the following as the first 2 lines of the file:
This communicates the environment to the header file.
Class names should be precedded by a 'Q'.
Class names should also follow the SmallTalk
class naming convention of having the first letter of words being capitalized, e.g. QClonableObject
. Enumeration type names should similarly treaded, except for beginning with an 'E', e.g. EZoomState
!#defined constants, const values, or enum constants should be all uppercase to indicate their status. Enumeration constants have the additional constraint of beginning wit EXXX_, where XXX is an optional enumeration type indicator, e.g. enum EZoomState
(EZS_NONE, EZS_ZOOM_IN, etc.)
typedefs of primitive types (which should be the onloy kind used, typically), should be lowercase, with a trailing "_t". This convention is rooted in ancient UNIX/C tradiion. This is also not a strict convention, for example the primitive types uint16, etc, do not follow this because their meaning is clear from the name. For less obvious types, however, this convention quickly alerts the reader to the meaning of the symbol.
Class data members must always begin with an '_', which immediatly distinguishes them from local variables or function parameters.
Function names shoudl begin with a lower case, but otherwise capitalize the beginnings of words.
Local variables and function arguments(except boolean flags) should be all lowercase.
Functions which take boolean arguments should define, as part of the interface, symbolic names which indicate what they do, e.g.:
#define bGenError bTrue
#define bNoGenError bFalse
getCelRefFromDB(const char* name, Bool fGenError);
This makes the use of such functions much more readable. Notice the implicit naming convention for such boolean constants. I happen to like this convention even though it violates the all upper case convention for constants.
Access functions should typically be the same name as the data they represent for the fetch (with no leading '_'), similarly for the set function, except with a leading "set", e.g.:
sometype nameOfData(void) const;
Base types and constants
In addition to basic types and constants defined in ANSI, such as size_t and NULL, several common types are defined to help facilitate portability. These include the following integral sized types and abbreviated notations:
int8 uint8 int16 unint16 int32 uint32
uchar ushort uint ulong
In addition to the integral types a boolean type is defined: Bool. This is almost guaranteed to be type int, since one prefers the natural machine size. (In particular it will not in general be of type char.) The following are predefined boolean constants:
#define TRUE (1!=0)
#define FALSE (1==0)
#define bTrue TRUE
#define bFalse FALSE
(phpwiki seems to have a problem with long pages)