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 the main( ) 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 run a.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 an ifstream entity and a string entity. Then, definitely do include fstream and string in the Foo.h. Foo.h should NOT rely on Foo.cpp to include ifstream and string prior to including Foo.h.

    Since Foo.cpp and Foo.h are part of the same code, Foo.cpp need not include header files already included in Foo.h.
    Neither Foo.h nor Foo.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 and public section in a class definition. public comes first, followed by protected and then private.
  • 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; <span style="background-color:yellow;">int frequency; // ok too</span>


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 not required for single statement if/else/while/for structures, assuming suitable indentation is used to show the structure. For example, the following structures are NOT permitted 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; 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.
  1. The file name
  2. The project number
  3. Your name
  4. The date the file was created
  5. Your section number
  6. Your UMBC e-mail address
  7. A description of what the code in the file does
For example, /***************************************** ** File: Proj1.cpp ** Project: CMSC 202 Project 1, Fall 2005 ** Author: Bob Smith ** Date: 9/22/05 ** Section: 0304 ** E-mail: bsmith32@gl.umbc.edu ** ** This file contains the main driver program for Project 1. ** This program reads the file specified as the first command line ** argument, counts the number of words, spaces, and characters, and ** displays the results in the format specified in the project description. ** ** ***********************************************/

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.

  1. The function's name
  2. The function's pre-condition(s) (if there are no pre-conditions, say so).
  3. The function's post-condition(s).
A pre-condition is a statement giving the condition(s) that is (are) required to be true when the function is called. The function is not guaranteed to perform correctly unless the pre-condition is true (see text page 113). It is NOT just a restatement of the parameter names and types.
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

//------------------------------------------------------- // Name: CircleArea // PreCondition: the radius is greater than zero // PostCondition: Returns the calculated area of the circle //--------------------------------------------------------- double CircleArea (double radius ): whereas in the .cpp file we expect to find the function implementation and comments meant for the programmer // CircleArea // Given the radius, returns the area double CircleArea ( double radius ) { const double PI = 3.14159; // handle unmet precondition if (radius < 0.0) return 0.0; else return PI * radius * radius; } Pre- and Post-conditions will be discussed in more detail in class.

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 acceptable for (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