C++ Program
Style Rules
Copyright 2003-2009 Dr.
clintstaley@gmail.com
The following style rules are
mandatory for all programs submitted.
Breaking a style rule will cause your program to “bounce”, and you will
have to redo the code according to correct style.
1. Identifier names
A. Choose names carefully. X, jj,
and b2 don't mean as much as timeLeft, biggest, and whereNext. Avoid
single letter variable names, except where they are clearly explanatory (e.g.
as "x" and "y" in coordinate geometry.)
B. If you decide to abbreviate a commonly used term in
variable or type names, use exactly the same abbreviation everywhere. (For instance, if the term "category"
appeared often in variable or type names, you might abbreviate it everywhere
to "ctg".)
C. In multiple-word names, capitalize the first letter
of the second and later words. Do not
use underscores. In names of functions,
classes, types, and global data, capitalize the first letter of the entire
variable name, too. Leave the first
letter lowercase in locals and member data.
Functions, globals, classes, types:
String ClearList TotalSize
Locals and member data: stringLength nameNdx bestScore
D. Do not use “Hungarian notation”. However, do add an "m" ahead of
each member datum name. (Member data
names might be mCount, mCurrentItems,
etc.) This helps avoid bugs due to
accidentally naming a local variable and a member datum identically. And add a "k" in front of each
constant (e.g. kMaxSize, kArraySize).
2. Constants
Use defined constants. There should be no actual numbers other than
0, 1, -1 or 2 in your code. Even these
might sometimes be constants if they could change in later versions of the
code. Use standard (rule 1) variable
naming conventions for constants. Do not
use #defines; use const.
Declare parameters,
variables, return values, and member functions to be const wherever
possible. Use const references when
passing data of over 4 bytes by value.
When you pass data “by reference”, so that the function may modify the
actual parameter, do not use references.
Instead, use pointers in the same way you would in ANSI C.
3. Global Variables
Never use a non-const global
variable without first asking me. And if
you ask me, I will say “No.”
4. Function Design
A. Functions must be at most 50 lines long, not counting
blank lines, assertions, or lines containing only a single brace. Don't cram code to satisfy this limit. Break up your functions instead. Functions with long switch statements or
if-else blocks are an exception to this rule.
B. Always put local variables at the top of the function,
not interspersed in the code, unless the program requires delayed construction
of the local.
5. Class Design
A. When a type is just a simple set of data, use the
keyword struct.
A struct may have a constructor and
destructor, but would rarely have any other methods. If you need more methods, use the class
keyword, and...
B. Never use a public data member except in structs as defined in 5A.
If you have a member that you would like to make freely modifiable, make
the data member protected, and create two public member functions to access and
modify it, using the same name as the data member, but with “Set” and “Get”
added. This arrangement lets you attach
more complex code to the accessing and modifying of the data in the future.
class Type {
public:
int GetData() {return
mData;} // Get
data value
void SetData(int val)
{mData = val;} // Modify
protected:
int
mData;
};
C. In the .cpp implementation of a class, define the member functions
in the same order that they were listed in the .h class declaration.
D. Classes that cannot be properly copied by memberwise assignment (such as those with dynamically
allocated storage) must have a copy constructor, virtual destructor, and
operator= function. Do this even if you
never plan to use these functions. These
three functions must either be correctly implemented and tested, or be
placed in the private section with "assert(0)"
as a body, so that accidental use will be flagged either by the compiler or the
assertion.
Where possible, implement
these three member functions by creating two private member functions Delete
and Duplicate, which perform destruction of the class, and copy construction,
respectively. The destructor and copy
constructor simply call Delete and Copy, respectively. The operator= function calls them both --
first Delete and then Copy.
E. Include inside the class (publicly or privately) all
types that the class needs for its internal data and for its parameters. Don’t declare such types outside of the
class.
F. Use inline member functions, defined inside the class
declaration, whenever the function is short enough to fit on just one line, and
does not rely on other class declarations (see item 5H). You may place multiple statements per line
in this case, but obey horizontal spacing rules (see 8). If a method is not inline, make it virtual.
G. Destructors in classes (not necessarily structs) must be virtual.
H. When a header file A.h for
class A includes pointers or references to class B, do not include B.h in A.h. Such inclusions result in tightly
interdependent code with attendant long builds.
Instead, use forward declarations (e.g. "class B;"). Do not put inline functions in A.h if they result in the need to include B.h unless such inline code is essential for efficiency.
6. Indentation and Blank
Lines
A. Use 3 space indentation, and indent only one level
for each nested if,
while, or switch. Do not use tabs for
indentation. Hidden tabs are one of the
most common sources of style bounces.
You may want to use the "detab"
program from my ~cstaley/bin directory.
while (...) {
statement;
if (...) {
statement;
}
}
B. Never let a line exceed 80 columns. If a line must be broken into two, indent the
second part one space past the first column of the first part:
Big long line....
with
continuation line below
C. Indent both the then and else blocks of an
if-statement, even if
they are only one line long.
Don't write: if (test) statement;
D. Use blank lines to break up blocks of code. Code should fall into groups of about 5 lines
on average, separated by a blank line or a line with only a brace. Always put a blank line after the local
declarations in a function. Don’t put
more than one blank line in a row. A
single blank line at a time is enough to break up the flow of code properly.
E. Place the opening brace at the end of the first line
of the if, while, struct,
etc. that it applies to. (See examples
under 6A and 11.). The only exception is
the opening brace of a function, which goes on a line by itself.
F. Indent member functions and member data 3 spaces
relative to the "class" or "struct"
keyword, but do not indent the keywords “private”, “public", or
"protected".
struct
{
int
Add();
protected:
float total;
};
7. Large Scale Organization
A. Files should be at most 600 lines long.
B. Include files must be protected by #ifndef/#endif pairs or #pragma
once, to avoid
multiple inclusion.
C. Files should come in .h/.cpp
pairs, with each pair defining one class.
(e.g. string.h and string.cpp
define a String class.) If two classes
are friends, they can go in the same .h/.C file pair, but otherwise it’s one
class per file pair. Do not cram
declarations, constants, and classes into a big, general purpose, .h file.
D. If a declaration is needed in only one .cpp file, don't put it in a .h
file at all -- include it in the .cpp file that needs
it.
E. Do not use using namespace in a .h file, since this forces all includers
of the header to use that namespace. Use
full namespace scope in .h files. Use using namespace only in .cpp files.
F. Avoid excessive .h file dependencies. In particular, do not include one non-system
.h file in another when a forward declaration will suffice. Ensure that forward declarations will
generally suffice by avoiding inline methods that make use of methods or member
data of other classes.
8. Horizontal Whitespace
Use whitespace to clarify
your code and to break up long expressions, but don't overdo it.
A. Put spaces after each comma, and around each keyword
(note that "if", "while" and "for" are
keywords). Put a space after each
semicolon in a for header. Never put a space before a comma or
semicolon.
B. Put spaces around operators, except for operators on
the top two rows of the precedence table (e.g. [], ++, &) or in very large
expressions where you may avoid spaces around the innermost operators. Don’t have more than three variables or
operators in a row without a blank space.
Good: epsilon = 2*beta[1]
+ *gamma - delta*pi;
Bad: epsilon=2**gamma-delta*pi;
C. Put single blank lines after each function, and
between local declarations and the function code.
D. Don't put
space after an opening paren, or before a closing
one. Do not put space between a function
name and the opening paren for the parameter list.
9. Comments
Be sure the main file includes
a comment giving your name, and section number if you're in a multi-section
course.
Add declaration comments
to each header file. Declaration
comments describe the class or classes declared in the header, including each
member function and parameter, and each member datum. Declaration comments describe only the
interface, not implementation details.
(Member data are technically an implementation detail, but since they
reside in the header file, we document them in the declaration comment.)
Add implementation
comments to each source file, describing how each function in the source
file works. Do not repeat information
from the declaration comments in the implementation comments; stick strictly to
describing the implementation.
Don't comment the obvious;
concentrate on explaining the hard parts.
Put variable, type, and function names in quotes in comments, to
distinguish them from ordinary words.
Any time a method or implementation is changed, the comment must be
changed as well. Keeping comments
current is essential to their usefulness.
If comments frequently are out of date, people start to ignore all
comments.
Comments must be clear. A set of words in comment markers is not
automatically a comment. If the comment
isn't clear, it
doesn't exist. Comments must be
perfectly spelled, and perfectly grammatical.
We routinely bounce programs for grammar and spelling errors.
Most professional programmers
do not like to see comments intermingled line-by-line with code, since this
distracts their eye as they read the code.
Put comments in function headers, not in the code
itself. You may mark a line with
a number thus: // 1 , and discuss it in the function
header. On rare occasions you may add a
short comment to the right of the code to explain something especially
confusing.
10. Code Safety
The following rules will help
eliminate coding errors, or make them easier to catch:
A. Use assertions
to check input assumptions on functions and to check the outcome of complex
blocks of code. Assertions should only
be used to check for bugs in the code, not to cover user or file format
errors. Use exceptions for these. Write an assertion only if you would change
the code in the event of the assertion’s failure. As a rule of thumb, you should have 3-8
assertions per page of code.
B. Always add a
“default” case to a switch. If this case
should never be reached, then place an “assert(0)” in
it.
C. When you delete data, immediately set its pointer to
0. This prevents double-deletion or
accidental use of deleted data. YIn this case, you may put the 0-assignment on the same
line as the deletion:
delete ptr; ptr = 0;
D. Initialize all member data of a class in the
constructor, even data you expect to reassign later.
11. Style Examples
Example of Good
Style:
int
test(int number)
{
int
count;
for (count = 1;
count < MAX; count++) {
if (number+1
> i && number-1 < count) {
cout
<< "hello" << endl;
}
else {
cout
<< "goodbye" << endl;
}
number = number
+ 1;
}
count = number;
while (count >
MAX)
count = count -
DECREMENT;
}
Example of Bad
Style:
int
test(int n) {
<-- { on same line as function header
int
i;
<-- one letter name, no space after locals
for (i=1;i<5;n=n+1,i++) <-- bad horizontal space, use of
constant
{ <-- belongs on prior
line
if (n+1>i && n-1 < i) <--
Single letter variable names.
/********************************* <-- Dumb banner
comment
* This is an if statement ! *
*********************************/
{ <-- Double indentation
cout << "hello" << endl;
}
else {
cout << "goodbye" << endl;
}
}
i = n;
while(i > 10)
<-- no space after "while", use of constant
i = i - 2;
}