C++ Coding Guidelines

Coding guidelines are used by programmers to make their code readable. Whenever you write a program it's important to have a set of coding guidelines to follow. Two of the main advantages to following a set of coding guidelines throughout the lifetime of a program is that it makes it easier to maintain the program and it allows new developers to become acquainted with the program faster.

Coding guidelines are of great importance when several developers are working on the same project. Without them the program has very little consistency and the job of maintaining the program becomes much harder. Studies have estimated that approximately 70 percent of the money spent on a program over its lifetime is for maintenance. So you can imagine companies want their programs to be as maintainable as possible.


Documentation Guidelines

Documentation guidelines are one of the most important aspects of writing maintainable code. These guidelines refer to placing comments in your source code. It's very important to comment your code as you go along. Do not wait until you are finished programming to go back and comment everything. There's a good chance that you will have forgotten what your code does and instead of relearning it you'll write useless comments that provide little or no help. Each program you submit should contain comments as described in the following sections.

Source Code Header

Each source code file should have a header at the top of it containing the following information:

  1. Assignment information
    • Program name
    • Assignment number
    • Date
  2. Personal information
    • Your name
    • Your lecture section and lecturer's name
  3. Specifications
    • Brief description of the code
    • Description of any input values and types used by the code
    • Description of any output generated by the code
    • Description of any assumptions and limitations of the code

The following is a sample source code header:



//==================================================================== // // Program Name: Sorting Names with Insertion Sort // Assignment: 1 // Date: September 14, 2002 // // Programmer: Nomed Nocaed // Course: CSC 112 B Professor: Nirre Pluf // // Program Description: // This is a little program that reads a list of names from // a specified file or from standard input and then sorts // the names in ascending order and prints them to standard // output. // // Command line arguments are used to specify where the // list of names should be read from. If the program // doesn't receive any command line arguments then it reads // the names from standard input. If the program receives // a single command line argument then it reads the names // from the corresponding file. If more than one command // line argument is specified the program prints a usage // message and terminates. // // Input: // List of names from standard input or specified file // // Output: // Sorted list of names to standard output // // Assumptions/Limitations: // It's assumed that the length of a name will not exceed // 40 characters and that the number of names will never be // more than 5,000. // //====================================================================

Major Loop and Conditional Statements

Major loop and conditional statements should be commented in most cases. You should place the comment before the code and it should be indented at the same level as the code. Comments within braces should be indented at the same level as the statements within the braces.

The following is an example:


// Set minimum to the smaller of x and y if(x < y) { minimum = x; } else { minimum = y; }

Functions

Every function should have its own header. The header must indicate the pre- and post-conditions of the functions. The pre condition states what must be true before the function executes (state of the program which the client guarantees will be true before calling this function). The post conditions describes what is true after the function executes (state of the program the function will provide when it returns).

The following is an example:


//==swap============================================================== // pre: a and b contain two integer values // post: values of a and b are exchanged //==================================================================== void swap(int& a, int& b) { ... }

//==cStrLength======================================================== // pre: s must be a char array containing a proper c-string // post: returns the length of s (minus null) as an integer //==================================================================== int cStrLength(char *s) { int n = 0; // counter for the number of characters // count characters until null is reached for( ; s[n] != '\0'; n++); return n; }

Variables

Every variable and constant identifier should be commented when it is declared. You should place a comment describing the variables purpose after it's declaration, on the same line.

The following are examples:


int movieFrame[100]; // Array of MPEG frame sizes (bytes) int numFrame; // Number of MPEG frames in array


Style Guidelines

Style guidelines are just as important as documentation guidelines when it comes to writing maintainable code. These guidelines refer to whitespace usage and identifier names.

Identifiers

You should always use descriptive identifier names for objects, functions and classes. For example the identifier numberOfNames is more descriptive than n. If an identifier consists of more than one word the first letter of each word should be capitalized. You should not use underscores between words. The following is a list of rules for the various types of identifiers:

  1. Object identifiers should begin with a lower-case letter (i.e.numberOfNames)
  2. Function and member function identifiers should begin with a lower-case letter (i.e.load, Queue::remove)
  3. Class identifiers should begin with an upper-case letter (i.e.Stack,Queue)
  4. Named constants and #defines can be all upper-case
  5. Enumeration literals can begin with an upper-case letter

Whitespace

You can write sloppy unreadable code with C++ unless you use whitespace correctly. If you consistently follow the guidelines below on whitespace usage your code will be easier to read and debug.

  1. Function definitions should be aligned with the left-hand margin
  2. Adjacent function definitions should have at least 2 blank lines between them
  3. Statements that make up the body of a function, loop or conditional must be indented with at least 3 spaces
  4. Open and close braces should always be on a line by themselves and should be indented at the same level as their corresponding statement
  5. Statements should be on a line by themselves
  6. Continuation of a statement on another line should be indented at least 3 spaces more than the first line of the statement
  7. Binary operators should have a space on each side between the operator and the operands
  8. Cases within a switch statement should be indented 2 spaces and the statements that make up the case should be indented 2 more spaces

You should never use tabs to indent your code. Using the above rules the C++ control statements have the following format:

If Statement

if(booleanExpression) { ... } else { ... }

Switch Statement

switch(integerExpression) { case constantExpression: { ... break; } default: { ... break; } }

For Statement

for(expression; expression; expression) { ... }

While Statement

while(booleanExpression) { ... }

Do While Statement

do { ... } while(booleanExpression);

Functions and Member Functions

In general you should try to keep the size of your functions and member functions to be less than 40 lines of code. Large functions are hard to understand and debug.


Class Guidelines

Since C++ is an object-oriented language you will spend a lot of your time writing classes. Some of the guidelines for classes have are ready been discussed. This sections describes the remaining guidelines.

Class Definitions

Inside a class definition the declarations of members should be indented 3 spaces. Access control sections should be defined in the order public, protected and then private. This order corresponds to the "interest" level of the section. In general more people are interested in the public section of your class than the private section. The following is an example of a class definition:


//==IntegerStack====================================================== // Class of objects which maintain a stack of integers //==================================================================== class IntegerStack { public: // Default constructor IntegerStack(int size = 64); // Copy constructor IntegerStack(const IntegerStack& s); // Destructor ~IntegerStack(); // Answer top element and pop it off int pop(); // Push the specified element on top of myself void push(int element); // Answer true iff I'm empty bool isEmpty() const; // Assignment operator IntegerStack& operator = (const IntegerStack& s); protected: private: int* elements_; // Pointer to an array to hold my elements int size_; // Size of my element array int top_; // Index of where the next element will be pushed };

Files

You should structure your classes so they can be reused in other programs. One idea that helps is to put your classes in two files called the specification and implementation files. The specification file contains the class definition while the implementation file contains the definitions of the class members. For example consider the IntegerStack class from above. The definition for this class would be in a file named integerStack.hxx and would appear as follows:


#ifndef INTEGERSTACK_HXX #define INTEGERSTACK_HXX //==IntegerStack====================================================== // Class of objects which maintain a stack of integers //==================================================================== class IntegerStack { public: ... private: ... }; #endif

The implementation of the IntegerStack class would be in a file named integerStack.cpp and would appear as follows:


#include "integerStack.hxx" //==default constructor=============================================== // pre: size is a postive integer value for the stack size, // default size is 64. // post: new empty stack created of size size, top initialized to 0 //==================================================================== IntegerStack::IntegerStack(int size) { top_ = 0; size_ = (size > 0 ? size : 64); elements_ = new int[size_]; }

You should also include a header as described in the documentation guidelines in both of these files.

Class Data Members

You should never have a public data member in a class. If you need to provide access to a data member then you should do it with a getter/setter pair of member functions. For example:


// Answer my current size int size() const; // Change my size void size(int s);

Copy Constructor and Assignment Operator

Remember that the default copy constructor and assignment operator perform a "shallow" copy or a bit-by-bit copy. This is fine for some classes but whenever your class contains a pointer there is a very good chance that you will need to write your own copy constructor and assignment operator to perform a "deep" copy.


Send comments to fulp@wfu.edu
Last modified on 8/27/2002