This section is a C++ and MFC coding style guide for Qoole-AID. The rules and guidelines it offers are intended to achieve two major goals:
Having common conventions for names, class design, and so forth will make it easier for any developer to understand (and, if necessary, modify) any piece of code.
Following these conventions (e.g., those governing class constructors) will help guard against common C++ pitfalls.
Violations of any principle described in this guide are permitted only after discussion and approval from the appropriate architect, and must be well-documented both as comments in the source code and in any associated external documentation. Such documentation should describe the nature and purpose of the violation, together with descriptions of how to maintain and extend the code despite the violation.
In general, all C++ source code files are named with the class name to which they correspond and the .cpp extension. Each has a corresponding header file by the same name with the .h extension. This makes the automation of source code management easier. This rule may be bent for small ‘helper’ classes, embedded classes, and small closely-related class families.
[See Source Code Documentation Standard – TBD]
Variables with descriptive names should be used in lieu of single character or shorthand constructs. The following qualifications should be used in variable declarations:
· Variables should begin in lower case with subsequent words beginning in uppercase (e.g. thisIsAGoodVariableName).
· Variables must not contain underscores.
· Variables must not exceed 31 characters.
· Variables must not be reserved words with a difference case.
See [TBD] for naming conventions of variable attributes declared within a class.
Descriptive function names should always be used and should include a unique prefix to help identify the functionality contained within the function (e.g. STU1BeforeDrawProc).
See [TBD] for naming conventions of function methods declared within a class.
Application constants consist of const values, enumerated values, and #defines. All of these should be named in ALL UPPER CASE, with underlines between the words (e.g., BOX_WIDTH).
[TBD]
[TBD]
[TBD]
[TBD]
[TBD]
· Only one variable may be declared per line of code.
· When declaring a pointer type, there must not be any blank space between the indirection operator and the variable name.
· Except for loop counters one-letter variable names must not be used.
· Variables should be grouped by usage rather than by type or name.
· Variables specific to a code block (i.e. within a for or while loop, or conditional statement) should be declared within the code block rather than at the beginning of the function.
· All variables declared at the beginning of a function should be initialized to a proper default value (i.e. pointers should be set to NULL).
Descriptive named constants (enums, consts, or #defines) should be used in lieu of hard coding numbers and constants. This facilitates consistency and portability. Place these in the relevant class header file or in a common header file if they are of global interest. Example:
const unsigned MAX_STUDENTS = 1024; const char LETTER_A = ‘A’; typedef enum { ACTIVE, INACTIVE, PENDING = 5 } StudentModes;
|
Enums and consts offer compiler type checking, and are thus safer than #defines. Also, by using enums in a prototype, you already have documented to the programmer using your API what the valid values are for that argument. Enums and consts should therefore be used for constant values rather than #defines whenever possible.
Constants which can be grouped together by usage (e.g. the only allowed values allows in calling a function) should be defined within an Enum. This allows for stronger type checking and value verification when defining functions which accept only specific values as arguments.
Note that class constants must be written as enums, and that access to them outside the class will need to be class-qualified using the :: syntax (e.g., if StudentModes above were defined in class CStudentManager, then you would write CStudentManager::ACTIVE to refer to that value outside the class). Enum’s in the C++ scope can be declared in a simplified manner as follows:
enum StudentModes { ACTIVE, INACTIVE, PENDING = 5 };
|
Proper care should be taken to ensure that an enum declared in the simplified manner are not used by standard ANSI-C source files.
Function-like macros are used to automate repeated code fragments. In general, functions are preferred over macros; in some cases, a function template can be written to generate a family of related functions, obviating the need for macros. Macros should be written so that both the arguments they take and the expressions to which they expand are parenthesized:
#define MIN(x, y) (x < y) ? x : y // wrong #define MIN(x, y) (((x) <(y)) ? (x) : (y)) // correct
|
Note that this specific example might better be implemented as a function template.
Macros where one or more of the arguments will be evaluated more than once (such as this example) should be explicitly documented to warn against the use of expressions with side-effects (assignment expressions, pre- or post-increment or decrement, etc.) as arguments:
// WARNING: In the Min macro below whichever expression, x or y, // has the minimum value will be evaluated twice. #define Min(x, y) (((x) <(y)) ? (x) : (y))
|
Note that this specific example might better be implemented as a function template.
Function-like macros are not type safe, and can result in code bloat and make debugging harder. They should be used with due care. Consider using functions (possibly including function templates) instead of doing non-trivial computations in macros. |
Sometimes it is desirable to define a type alias to better document and enforce methods of data storage and use. Here is an example:
typedef unsigned char Byte;
|
This provides better documentation and compile-time type checking in functions that take bytes as arguments.
Note that in C++, class and struct declarations automatically add the class/struct name as an independently useable type name. Thus, a declaration in C like
typedef struct {int a, b;} Foo;
|
would be written in C++ as
struct Foo {int a, b;};
|
Both have the effect of making ‘Foo’ a type name for the structure, but the latter is much cleaner and more succinct.
[TBD]
[TBD]
Braces should always be used for conditional code blocks (if, else, else if, for, do, while, and switch) even if the block is a single line.
The controlling expression of a block and its closing brace should line up vertically. The opening brace should be either at the end of the same line as the controlling expression, or on the following line lined up vertically with the controlling expression. Block code should not appear on the lines that the curly braces appear on. Code inside the block should be indented one level.
Use This |
Or This |
Not This |
if (expression) { // code... }
|
if (expression) { // code ... } |
if (expression) { // code... } |
Document your intention by using parentheses. Even though operator precedence is well-defined in C++, it’s easier on human readers if you use parentheses to make the order of operations clear. Assuming left-to-right evaluation of sequences of */ or +- is generally safe.
a + b * c / d; // Incorrect a + (b * c / d); // Correct
|
[TBD]
[TBD]