C++ Programming Standards


The following standards are to be followed in writing C++ programs. They are important enough to be part of the grading criteria for all programs. Any constructs not covered in this standard are to be implemented in a consistent and readable fashion. The comment style included below is consistent with the Doxygen auto-documentation system.

PURPOSE

The purpose of these rules is (1) to introduce you to a representative set of coding standards that are typical in professional programming and (2) to help you develop good style as a habit, something you will find necessary to successfully complete large programs. There is no doubt that you can write C++ programs to solve the small problems in this course without attention to style. But, you must keep in mind that you are building professional skills, not merely finding the answers to problems handed out as exercises.

PROPER ATTRIBUTION

Any code you use that you have not personally written must be attributed to the author. This includes, among other things, code from the book, code from the net, or code from your instructor. Failure to describe where you obtained the code and the proper author is considered plagiarism, which is cheating!

FILE NAMES AND C++ COMPILER

In this course each C++ file name should clearly represent what it is and each must have the ''.cc'' suffix. For example, the main file for Project 1 should be prog1.cc. Keep data structures in separate files. If you write a list class for Project 1, put the list code in list.h, list.cc, and list.template. A lab project that determines the payroll of a small company could be payroll.cc (or even something like lab3.cc). We will use the gnu C++ compiler (g++). So, in order to compile Program 1, you would enter the command
g++ -g -Wall -Werror -O2 -std=c++11 prog1.cc -o prog1

This produces an executable file called prog1 which you can run using the command:

./prog1

The -g flag tells the compiler to include information needed by the GDB debugger. When given the -Wall flag, the compiler will print out every warning that it can generate for your code. The -Werror flag causes the compiler to consider every warning to be an error. Properly formatted code does not produce warnings. For most purposes, you should compile with the -O2 flag. The compiler will produce more warnings this way. However, the -O2 flag can cause unpredictable behavior in GDB, so when stepping through code in the debugger, compile with -O0 instead. Finally the -std=c++11 tells the compiler to use c++ version 11. Other values of this flag are c++14, etc. If you require more advanced features present in more recent versions of C++ be sure to use the appropriate std.

For production code, a more common compile command would look like:

g++ -Wall -Werror -O2 -std=c++11 prog1.cc -o prog1

In this case, we do not generate debug symbols.

The use of Makefiles to aid the compilation process is highly recommended in general, and required for CS3610/5610D. Makefiles contain a set of instructions to build your program. The file is read when you type 'make' at the command line. Makefiles can save time by checking dependencies and compiling only modified code.

Help page for makefiles. Each class should usually be defined in a separate file. Template functions should be in a file with a suffix of .template or .temp. Template functions are encouraged since they allow greater code reuse.

Each set of functions and/or classes that implements a different algorithm or data structure should be in a separate set of files. This allows better organization of your code, and eases code reuse.

Template files should be included at the end of header (interface definition) files (.h).

Recall that abstract data types are defined by describing the interface to the data type in the .h file, the implementation in a .cc or .template file, and are used by including the .h file.


INTRODUCTORY DOCUMENTATION

At the beginning of each file there should be a comment block that contains:
  1. The file name, your name, your email, and recitation section.
  2. A brief description of the code in the file that describes the method(s) or algorithm(s) used to obtain the solution(s), the major data structures (if any) in the program, and other general comments including extra features.
  3. The date the program was completed.

The format to be used is based on doxygen standards, and an example is given below:


/******************************************************************* 
*  \file 
*  \brief 
*                                                                     
*  Author:      your name
*  Email:       your email address
*                                                                    
*  Lab Section: section number and instructor's name
*                                                                    
*  Description: description of the program                    
*                                                                    
*  Date:        date of completion
*                                                                    
*******************************************************************/

The following is an example of an introductory comment block that follows the format above:

/********************************************************************
*  \file prog1.cc
*  \brief Project 1  -- Video Calculator
*                                                                    
*  Author:      Elwood Scuggins
*  Email:       Clueless@ace.cs.ohio.edu
*                                                                    
*  Lab Section: 10 (Chris Hayes)
*                                                                    
*  Description: This program inputs the total number of minutes, 
*               the number of minutes for commercials, and the 
*               number of minutes for episodes.  The program 
*               computes the total number of minutes for videos, 
*               the number of videos, and the number of seconds 
*               left over.
*                                                                    
*  Date:        January 26, 2020
*                                                                    
********************************************************************/


DECLARATIONS

  1. You should use mnemonic names for all identifiers. These are names that have meaning in the problem. The names should suggest the use of the identifier.

  2. You should use built-in constants for any values for which they make sense. For example, use the built-in constant NULL to set pointers to null, rather than 0.

  3. Constant values used in your program should be given in const declarations. Constant identifiers should always appear in all-capital letters. For example:
          const float BASE = 2.0;       ///< divisor to obtain base 2
          const char HYPHEN = '-';      ///< signals word continued on next line
          const int NAME_LENGTH = 20;   ///< names can be 20 characters
          

  4. You should not have any "bare" constants in your program. If you need to use a value of say 20 somewhere in your code, define a constant with that value whose name means something, like MAX_NUMBER_NODES.

  5. For anything other than constants, identifiers should be all-lower case letters (for example, student, temperature, weight, salary). Underscore characters should be used to delimit multiple words in an identifier. For example, ship_rates instead of shiprates, id_entry instead of identry, num_items instead of numitems, and min_score instead of minscore.

    It is permissible to capitalize the first letter of words in an identifier with class, structure, union, or type names. For example, you may wish to use Student, StudentName, or ListNode as names for your classes.

  6. Each identifier declaration (including function declarations) must be accompanied by a comment that explains its use.

  7. Avoid declaring globally-visible variables. Globally-visible constants, enumerated types, structures, classes, and file names are okay, but do not use global variables unless the project assignment specifically tells you to do so.


GENERAL RULES

  1. Each constant and variable declaration should be on a separate line that includes a comment that explains what each is. For example:
          float volts;                     ///< voltage in the circuit 
          int amps;                        ///< amperage in the circuit 
          char circuit_name[NAME_LENGTH];  ///< name of the circuit 
          

  2. Each statement should be on a line by itself. For example, instead of
          left = next_left;    right = next_right;
          
    use
          left  = next_left;     ///< move to the left
          right = next_right;    ///< move to the right
          

  3. Each class should have a comment block in the .h file describing the purpose of the class, operations it supports (generally these will be provided through its public member functions), and how it is typically intended to be used. The reasons for any friend classes in the class should also be explicitly stated, as well as any dependencies on other classes. An example of the format that can be used is as follows:
          /******************************************************************
          *                                                                  
          *  Class: Complex
          *                                                                  
          *  Purpose:  To allow a programmer to use complex variables as a data
          *            type. 
          *            
          *  Functions:
          *           Constructors
          *             Complex(double, double)  general version
          *             Complex(double) if the Complex variable only has a real part
          *             Complex() default constructor initializes to 0.
          *           setters
          *             set (double, double) general version
          *             set (double) if the Complex variable only has a real part
          *           getters
          *             real_part to return the real part of the complex variable 
          *             imag_part to return the imaginary part of the complex variable
          *           output outputs a human readable version to an open output stream
          *  
          *******************************************************************/
          

  4. Each function, whether it is a member function or ordinary function, should be identified by a comment block describing its purpose, parameter(s), and the function(s) it calls. The format to be used is as follows:
          /******************************************************************
          *                                                                  
          *  Function:   find_space_cost
          *                                                                  
          *  Purpose:    calculates and returns the charge for shipping cargo  
          *              between two planets.                                  
          *                                                                  
          *  Parameters: @param distance - distance in miles between two planets
          *              @param weight   - weight in pounds of item being shipped
          *
          *              @return - the charge for shipping cargo between
          *                        two planets 
          *
          * Member/Global Variables: none
          *
          * Pre Conditions: variables distance and weight have valid values
          *
          * Post Conditions: returns the cost in dollars of shipping a
          *                  package that weighs weight pounds a distance
          *                  of distance miles.
          *
          * Calls:       function cargo_rates
          *                                                                  
          *******************************************************************/
          

    This detailed comment should be placed in the implementation file, as which functions are called, etc. is not of general interest to someone who merely wants to use your class/function. A short version of the above comment should be placed in the .h file.

  5. For CS3610/CS5610D students, you should add additional lines for the space and time complexity of each function. If you use a variable like n, be sure it is clearly defined in your comments, or use English names to make it clear what your time/space complexity depend upon. E.G.:

    
          /// Space Complexity: O(number of items in list)
          ///
          /// Time Complexity:  O((number of items in list)^2)
          ///
          

  6. Comments should be set apart from the code by at least two spaces, making it easy to see where the code ends and comment begins.

  7. The main function should begin with
          int main ()
          

  8. Use the endl construction (instead of \n) to indicate end-of-line, when not already in a string. For example, use
          cout << "Today's date is " << today << endl;
          
    instead of
          cout << "Today's date is " << today << "\n";
          


FORMATTING AND COMMENTING OF STATEMENTS

Alignment and indentation of lines of C++ statements adds much to the readability of programs. The following guidelines are general so that you may develop your own programming style. Use indentation and blank lines as you see fit to increase the readability of your programs.

If any statement or block of statements was at all difficult for you to develop, or if the purpose of the statement or block is not obvious, consider commenting in-line (any non-header comment) describing your thought process, so that it is easier to read your code, and for you to recall what it is supposed to do when debugging. Remember the purpose of comments is to improve the clarity and readability of your code. In-line comments are encouraged where they meet this goal.

The body of a control structure, such as an if, a switch, a while, a do, or a for statement, should be indented. Always use curly braces even if there is only one statement:

if (expression) {
   statements
}
    

if (expression) {
   statements
} else {
   statements
}
    

switch (selector variable) {
   case case-1-value: case 1 statements;
        break;
   case case-2-value: case 2 statements;
        break;
   ...
   case case-n-value: case n statements;
        break;
   default: default statements;
        break;
}
    

while (expression) {
   statements
}


do {
   statements
} while (expression);


for (initialization; test; increment) {
   statements
}

As an alternative to the above formats, the use of the formats below is also acceptable:
if (expression)
  {
    statements
  }
    

if (expression) 
  {
    statements
  }
else 
  {
    statements
  }
    

switch (selector variable) 
  {
    case case-1-value: case 1 statements;
      break;
    case case-2-value: case 2 statements;
      break;
    ...
    case case-n-value: case n statements;
      break;
    default: default statements;
      break;
  }
    

while (expression) 
  {
    statements
  }


do
  {
    statements
  } while (expression);


for (initialization; test; increment)
  {
    statements
  }


PROGRAM DESIGN

  1. Use stepwise refinement. The programming assignments given are ones that can be solved in a step-by-step manner. The method of solution used in your program should exhibit this kind of structure.

  2. Modularize your program. When a problem solution readily splits into distinct tasks, your program should handle each task in a separate function and in a straightforward manner. Each set of functions for a particular task should be in a separate file.

  3. Make your program efficient. Your algorithm should be direct and not unnecessarily complicated. Proper use of data structures will often simplify an algorithm. Document the efficiency of your routines in comments.

  4. Use parameters appropriately. All variables used in a function should either be declared as parameters or be declared locally within the function.

  5. A good rule of thumb is if your function is over a screen full, then break it into subroutines.


OUTPUT

  1. All input values should be echoed in a readable manner unless otherwise indicated.

  2. The program output should be readable and clearly labelled. Headings should be used when appropriate.

  3. Finally, of course, your program should produce correct results!


David M. Chelberg <chelberg@ohio.edu>
last-modified: Thu Jan 16 11:49:40 2020