C++ Coding Standards
CMSC 341 - General C++ Coding Standards
Every programming department has some set of standards or conventions that programmers are expected to follow. The purpose of these standards is make programs readable and maintainable. After all, you may be the programmer who maintains your own code more than six months after having written the original. While no two programming departments' standards/conventions may be the same, it is important that all members of the department follow the same standards. Neatness counts!!! The following standards are to be followed in CMSC 202.Part of every project grade is based upon how well these standards are followed.
It is your responsibility to understand these standards. If you have any questions, ask your instructor, any of the TAs, or the Computer Science Help Center.C++ File Extensions
There are numerous file extensions used to designate C++ source code files and header files. For this course, the file extensions.cpp
for source code files and .h
for header files will be used. No other extensions are permitted.
File Naming
For every project, a file named Driver.cpp, containing only themain( )
function is
required.
The executable for any project must be named "driver.out".
This is very important because the graders will look for that file to run your program. The graders will not runa.out
or any other executable. The executable name is
controlled by your makefile - get it right.
For most projects, you will be creating your own classes. In these projects, the following standards also apply.
- All C++ classes are defined in a separate header file.
Name each file after the class it contains and give it a
.h
file extension.
Example: if you have a class that represents a Car object, the class should be named Car and the header file should be Car.h - All C++ classes are implemented in a separate source code file.
Name each file after the class and give it a
.cpp
file extension.
Example: if you have the Car class, the source code file should be named Car.cpp - No member functions OTHER than setters/getters are to be implemented in a class header file (i.e., no inline methods are permitted. All implementations belong in the matching implementation file.)
Grading scripts used by the graders assume that you follow these convention.
File Organization
- Every header file must be guarded using the
#ifndef FOO_H #define FOO_H . . #endif
style. This style is used to avoid multiple inclusions of the header file. - A header file is to be included in a given file if and only if the header
defines an entity referred to in the given file. For example, suppose the header
file
Foo.h
refers to anifstream
entity and astring
entity. Then, definitely do includefstream
andstring
in theFoo.h
.Foo.h
should NOT rely onFoo.cpp
to includeifstream
andstring
prior to includingFoo.h
.Since
Foo.cpp
andFoo.h
are part of the same code,Foo.cpp
need not include header files already included inFoo.h
.
NeitherFoo.h
norFoo.cpp
should include header files which are unnecessary.The point is that each .h file is "independent" and therefore the order in which .h files are listed in a .cpp file doesn't matter.
Class Definition Standards
The following standards must be followed when a class is defined within it's header (.h) file- All class names begin with uppercase. Multi-word class names follow the variable/function naming convention below, which is camelCased.
- Only one
private
,protected
andpublic
section in a class definition.public
comes first, followed byprotected
and thenprivate
. - Every data member of a class must be
private
. - You may use global symbolic constants (
const
), but not global variables. - Class methods follow function naming conventions below.
- Class methods must have complete function header comments (description, pre/post conditions) in the HEADER file along with the function headers. While fewer comments are required in the .cpp file, this may be where you have the most since it will have more detail.
- Class methods must be
const
whenever possible. - Except for explicit class input/output methods, class methods should not perform input or output.
- Class data members MAY begin with m_ and follow the variable naming
conventions below.
Example:
int m_length; int m_nrStudents; int frequency; // ok too
Variable, Constant and Function Declarations
These standards detail how variables and constants should be declared, proper function prototype declarations as well as naming conventions.- Use meaningful descriptive variable names!!
For example, if your program needs a variable to represent the radius of a circle, call it 'radius', NOT 'r' and NOT 'rad'. - Begin variable names with lowercase letters
- The use of single letter variables is forbidden, except as simple 'for' loop indices, temporary pointer variables and in special cases such as x- and y-coordinates.
- The use of obvious, common, meaningful abbreviations is permitted. For example, 'number' can be abbreviated as 'num' as in 'numStudents'.
- If commented, variables must be declared one per line. Comments should appear on the same line without wrapping (use two lines if necessary).
- Do not use global variables!!!
- Separate "words" within variable and function names with camelCase.
(e.g. grandTotal)
- Function MAY begin names with uppercase letters. This has been replaced since many IDEs generate code for you and the function names start in lowercase.
- Use active function names, generally beginning with a verb and including a noun -- GetName( ) or getName(string name)..
- Function prototypes must include parameter names as well as types.
- Default values for parameters must be specified in the prototype. For example int getAge(int age = 0);
- Reference parameters must be const whenever appropriate.
Separate "words" within function names with mixed upper and lowercase. (e.g. ProcessError)- Constants should be used for magic numbers and strings whenever
possible. Points will be deducted from projects with code written like
that on the left. A "magic number" is a constant that has some meaning
within your program and is often used in multiple places. Use a const int/float/double to give it a name.
Likewise, well known mathematical constants (like PI) should also be
given a name (
const double PI = 3.14159;
.When used in the usual way, zero and one are NOT magic numbers. Likewise, some constants found in formulas (Celsius = (5/9)*(Fahrenheit-32) have no meaningful names and are not considered "magic".
The point is to give names to numbers and strings which already have well known names (ie PI), are used in the logic of your code and/or are likely to change in some future version of your code. Giving names to these important values makes your code more readable and changeable.
Wrong Right int array[30]; // a magic number for (int i = 0; i < 30; i++) // here it is again array[i] = -3; // what does -3 mean? if (command == "ADD") // magic string may change someday // do something else if (command == "MULTIPLY") // another magic string // do something else const int ARRAYSIZE = 30; const int INITIALVALUE = -3; const string ADD = "ADD"; const string MULTIPLY = "MULTIPLY"; int array[ARRAYSIZE]; for (int i = 0; i < ARRAYSIZE; i++) array[i] = INITIALVALUE; if (command == ADD) // do something else if (command == MULTIPLY) // do something else
Documentation
The following sections detail the required program documentation. Failure to adhere to these standards will result in point deductions from your project submission.Use of Whitespace
The prudent use of whitespace (blank lines as well as spaces) goes a long way to making your program readable.
- Use blank lines to separate pieces of code for readability
to separate unrelated sections of code and thereby group logically related
lines of code together.
This code fragment is unreadable and results in deductions// count total number of students for (int i = 0; i < size; i++) totalStudents += class[i]; cout << "total students = " << total students << endl; while (moreStudents == true) { // read student last name ReadStudentName(); // print full name PrintStudentName(); // now verify student info goodInfo = VerifyStudentInfo(student); if (goodInfo == true) cout << "good info" << endl; } cout << " this is the end" << endl; and should be formatted like this// count total number of students for (int i = 0; i < size; i++) totalStudents += class[i]; cout << "total students = " << total students << endl; while (moreStudents == true) { // read student last name ReadStudentName(); // print full name PrintStudentName(); // now verify student info goodInfo = VerifyStudentInfo(student); if (goodInfo == true) cout << "good info" << endl; } cout << " this is the end" << endl; DO NOT use tabs (unless your text editor changes tabs to 3 or 4 spaces). Tabs may be interpreted differently by different editors.- Use a tab or 4 spaces for each level of indentation.
And be consistent. Too much indenting makes the code unreadable and
hastens line wrapping.
// This is an example of good formatting if ( x > 90 ) { statement 1; statement 2; } else { statement 3; } // This is an example of too much indenting if ( x > 90 ) { statement 1; statement 2; } else { statement 3; } // This is an example of inconsistent indenting if ( x > 90 ) { statement 1; statement 2; } else { statement 3; } - Use spaces around all operators. For example, write
x = y + 5; NOT x=y+5; - Using the emacs or xemacs editor along with the .emacs file provided for you will automatically indent your code appropriately. The pico editor will not do so.
Use of Braces
- Use a consistent style for braces. See the indentation styles for appropriate placement of braces.
- Braces are
notrequired for single statement if/else/while/for structures, assuming suitable indentation is used to show the structure. For example, the following structures are NOT permittedif (grade > 90) cout << "You got an A" << endl; else cout << "No A for you" << endl; for (i = 0; i < 30; i++) array[i] = -3; They SHOULD look like:if (grade > 90) { cout << "You got an A" << endl; } else { cout << "No A for you" << endl; } for (i = 0; i < 30; i++) { array[i] = -3; }
Comments
Comments are the programmer's main source of documentation.
From "The Practice of Programming" by Brian Kernighan and Rob Pike, page 23
Comments are meant to help the reader of a program. They do not help by saying things that the code already plainly says, or by contradicting the code, or by distracting from the code with elaborate typographical displays. The best comments aid the understanding of a program by briefly pointing out salient details or by providing a larger-scale view of the proceedings".Rule of Thumb:
Approximately every 5 lines of code need AT LEAST 1 comment.
Not every line of code needs a comment.
Constant declarations MUST have 1 comment.
Commenting standards for files, functions, and code are described below.
File Header Comments
EVERY .cpp and .h file should contain an opening comment describing the contents of the file and other pertinent information. This "file header comment" MUST include the following information.- The file name
- The project number
- Your name
- The date the file was created
- Your section number
- Your UMBC e-mail address
- A description of what the code in the file does
Function Header Comments
Function header comments are the primary form of documentation for the user of our functions and classes. It is important that this documentation be both complete and accurate as it forms a "contract" between the function/class user and and the function/class implementer.EACH FUNCTION and CLASS METHOD must have a header comment that includes the following information. The full function header comment described below must appear in the appropriate .h file. Less formal function header comments are required in the appropriate .cpp file.
- The function's name
- The function's pre-condition(s) (if there are no pre-conditions, say so).
- The function's post-condition(s).
All functions must test for pre-conditions to the extent possible Until we learn about exceptions, if a false pre-condition can be handled in code, do so (see CircleArea function below).
A post-condition is a statement describing what will be true when the function call is completed (assuming the pre-condition is met and the function completes -- see text page 113).
For example, in Circle.h we would expect to find prototypes and full function header comments like this intended for the user of the function
In-Line Comments
- In-line comments are used to clarify what your code does, NOT how it does it.
- An in-line comment MUST appear above the code to which it applies
and is indented to the same level as the code.
The following example is acceptable.// check every element of the array for (i = 0; i < ARRAYSIZE; i++) { // add one to odd values if (array[i] % 2 == 1) { array[i]++; } } The following example is not acceptablefor (i = 0; i < ARRAYSIZE; i++) // check every element of the array { if (array[i] % 2 == 1) // add one to odd values { array[i]++; } } - Be sure your comments don't contradict the code.
- Don't comment bad code -- rewrite it.
- Don't comment the obvious. Comments like these are worthless.
// return true return true; // increment counter ++counter; - Constants and variables should be commented on the same line on
which they occur. Such comments should not wrap; use two lines if necessary.
const int NUM_STUDENTS = 35; // number of students in the class const int NUM_SECTIONS = 4; // number of sections of CMSC 104 const float CUTOFF = 88.5; // cutoff for an "A" for the 2001 // spring semester bool isCurrPresent = false; // is the current student present? int currStudentInd = 0; // index of current student