C++ Coding Standards
Introduction

Adhering to a good programming style will help promote good readable code and will eliminate most of the common programming mistakes.  Every student will be expected to follow this guide.
 
 

General Style

This section is going to cover some general styles.  This will include directory hierarchy and file naming.  Creating a common hierarchy will keep you from having to search for where your headers files and source files are located on your machine.  Keeping to a good naming convention for your files will help in cross platform development where you compile your application on different operating systems and will help you know by looking at the name of the file what the file pertains to.

Source Files
 
 

Source files will be in all lower case separated by underscores.  All C++ files that you create will keep to a .cpp extension and all header files you create will keep to a .h extension.  Every .cpp file will have an associated .h file.  The .h file and the .cpp file will have the same names but different extensions.  For example if you had some functions that implemented manipulating a student database then the file name will be descriptive.

        SourceFileName : student_database.cpp
        IncludeFileName: student_database.h
 
 

Keeping the source and include file the same name and only differing by an extension will keep you from searching for which include file is associated with this source file.
 
 

Directory Hierarchy
 
 

For each project or homework assignment that involves some programming there should be a separate but common named directory structure.  All include files for a given project should go into an include directory and all source files .cpp should go into a source directory.  These two directories are typically sub directories of the project directory.  When compiling your software you do not want to flood the source directory with object files generated by the compiler.  Object files are typically identified with a .obj extension on the PC side and .o extension on the unix flavor side.  So an obj directory should also be created.  The exe file should be sent to an exe sub directory.  The files that actually compile the software we are writing will also go into its own directory.  Since the code we are developing is cross platform then the files that will build the software will be in a sub directory called compile.  Now within this compile directory I like to create another sub directory depending on which compiler is being used to build the files.  For example if I am using borland then the full sub directory name will be

        compile\borland
 
 

Example:  Our project is to build and create a simple database to manipulate student information.  Let's say that to implement this application we only need one source file and one header file:

            students_database.cpp
            students_database.h
 
 

What would the directory structure be like?  The first name is up to you but I would create a descriptive name:

            projects/student_database
 
 

Notice how I keep to an all lower case naming convention.  This directory will be what we call the root directory.  Where do we create the source file students_database.cpp?

        projects/student_database/src/student_database.cpp
 
 

and the header file

        projects/student_database/include/student_database.cpp
 
 

and object files and exe files will go into

        projects/student_database/obj
        projects/student_database/exe
 
 

and the ide files or makefiles or any other files will go into the following sub directory depending on how the files are being built.

        projects/student_database/compile/borland
        projects/student_database/compile/unix
        projects/student_database/compile/microsoft
 
 

If you are assigned another project like 3d-animation then the directory structure would be

        projects/3danimation/src
        projects/3danimation/include
        projects/3danimation/obj
        projects/3danimation/exe
        projects/3danimation/compile/borland
        projects/danimation/compile/unix
        projects/3danimation/compile/microsoft
 
 

Note that in the above examples I am assuming that the target type is an executable.  The directory

        projects/3danimation/exe
        projects/student_database/exe
 
 

may be executables but you may also have static libraries(.lib on PC and .a on unix) and shared libraries(.dll on PC and .so on Unix).  In that case you will need to develop names for those targets.

        projects/student_database/shared_lib
        projects/student_database/static_lib
 
 
 

Source Files

All include files will have the following #ifndef #endif wrapper to avoid multiple includes.  If we were to create the student_database.h file it would look something like this

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  File Name:         student_database.h
//
//  Author Name:    Garrett Potts
//
//  Last Revision:    January 15, 1999
//
//  Description:      This file is used to show how to document the header file and how to
//                            show where to place the #ifndef #define and #endif.  This file will hold
//                            all prototypes for manipulating a student database.
//
//  Change Log:       Created the file and wrapped with #ifndef and #endif
//
//  Portability:         Unix, Os/2, Windows 95/NT ...etc
//
//  Copyright:          This file is free to use as long as the copyright information and the authors
//                              name stays attached.
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef  STUDENT_DATABASE_H
#define STUDENT_DATABASE_H

//all prototypes, enumerations, classes...etc will go in here.

#endif
 
 

Once this is done for the header file the student_database.cpp must be done in the same fashion

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  File Name:         student_database.cpp
//
//  Author Name:    Garrett Potts
//
//  Last Revision:    January 15, 1999
//
//  Description:      Will hold the implementation of all functions and classes found in the
//                            student_database.h file.
//
//  Change Log:       Created the file and added the #include statements where appropriate.
//
//  Copyright:          This file is free to use as long as the copyright information and the
//                             authors name stays attached.
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "student_database.h"

//all functions and class implementations go here.
 

Main Entry Point

Eventually when we get to classes we will try to figure out a clever way of hiding main and figure out how to treat the main entry point as an application object.  The first approach is goin to relevant only because we haven't studied classes yet.

In both cases main will be defined in its own filename called main.cpp and the application entry will be in file application_main.cpp with associated header file application_main.h.  To allow for command line switching we will always create main with all three arguments.
 
 

//file main.h

//include your headers here
#include "application_main.h"
#include "main.h"

int main(long argc, char *argv[], char *env[])
{
     return ApplicationRun(argc, argv, env);
}
 
 

ApplicationRun function will be defined in the file application_main.cpp and will be prototyped in the file called application_main.h

application_main.h will look like this.
 
 

#ifndef APPLICATION_MAIN_H
#define APPLICATION_MAIN_H

int ApplicationRun(long argc, char *argv[], char *env[]);

#endif
 
 

Note the Name ApplicationRun can be more descriptive if you like.  For classes we will see how to perform the following.
 
 

//file main.h

//include your headers here
#include "application_main.h"
#include "main.h"

int main(long argc, char *argv[], char *env[])
{
      Application.Run(argc, argv, env);
}
 
 

Where Application is the name of our main application object and run is the member function that is going to be called to control the application.

Variables

All variables will adhere to a good naming convention.  A good variable name will immediately be able to tell us the type and what it's going to be used for.  Example:
 
 

int main()
{
        int x, y, z;

        x = 0;
        y = 100;
        z = 100;
        x = (y + z) / 2;

        cout << "The average grade is: " << x << endl;

        return 0;
}

Observing the names of x, y, z we have no clue what they pertain to.  I didn't know until reading the cout statement that x was to hold an average integer grade.  A better naming convention would have produced something like this:

int main()
{
        int iAverageGrade, iGrade1, iGrade2;

        iGrade1 = 100;
        iGrade2 = 100;
        iAverageGrade = (iGrade1 + iGrade2) / 2;

        cout << "The average grade is: " << iAverageGrade << endl;

        return 0;
}

The i pre-pending each variable name gives indication of the variable type.  In this case the variable type is integer.  The following table will be used by the class.  The prefixes I will make optional but are a good idea to help in identifying the type of the variable:
 
 

Variable Type Variable Prefix Value
   
int i
short s
long l
unsigned u
unsigned long  ul
unsigned short us
float f
double d
long double ld
const k
short int si
long int li

Examine the following code fragment that applies the conventions in the table:

int main()
{
        unsigned short   usMyFirstExample;
        unsigned long     ulMySecondExample;
        long                   lMyThirdExample;
        char                   cMyFourthExample;
        unsigned char    ucMyFifthExample;
        const long          klMySixthExample = 0;

        //replace this comment with the first line of code.

        return 0;
}

Notice how the variable names are lined up with each other.  I will not accept code that looks like this:
 
 

int main()
{
        unsigned short   usMyFirstExample;
        unsigned long    ulMySecondExample;
        long lMyThirdExample;
        char  cMyFourthExample;
        unsigned char  ucMyFifthExample;

        //replace this comment with the first line of code.

        return 0;
}

The variables are harder to see and read and there will be one blank line after the last variable declaration and coding will begin where the comment line is.  The return will have a blank space before it.  Constant expressions are an exception to the rule defined above.  If any constant expression is defined It will have all capital letters separated by underscores for example code:

#include <iostream
using namespace std;

const long   ARRAY_SIZE                   =  100;
const char* INSTRUCTOR_NAME     =  "Garrett Potts";

int main()
{
    long lTestArray[ARRAY_SIZE];
    long lTestArrayIndex = 0;

    for(lTestArrayIndex = 0; lTestArrayIndex < ARRAY_SIZE; lTestArrayIndex++)
    {
            lTestArray[lTestArrayIndex] = 0;
    }

    cout << INSTRUCTOR_NAME << endl;

    return 0;
}
 
 

Enumerations

Enumerations are going to have a similar naming convention much like constant expressions defined at the end of the Variables section.  observe the following code fragment:

//file my_first_header.h
#ifndef  MY_FIRST_HEADER_H
#define MY_FIRST_HEADER_H

enum VirtualKey {
                                 KEY_1 = '1'
                                ,KEY_2 = '2'
                                ,KEY_3 = '3'
                                ,KEY_4 = '4'
                                ,KEY_5 = '5'
                            };

#endif

Typically the above enumeration will be found in the header file.  Notice the format of the enumeration.  The enum followed by the name of the enumeration followed by the begin bracket.  Each enumeration is an integer constant.  This means the only valid values are integer based, in the above the char type is used and all chars are represented as an integer.  All enumerations that have multiple lines will have the above format.  The names are in all capitals and the = sign is separated by blank space to the left and to the right of the equals.
 

Using the above in a program will look like this
 
 

#include <iostream>
#include "my_first_header.h"

int Run()
{
    VirtualKey KeyTest;

    KeyTest = VK_1;

    return 0;
}

int main()
{
    return Run();
}

Spacing on control structures will be discussed in another section.

Control Structures


 
 

Control structures will allow for conditional flow through the program.  We will adhere to a strict standard when implementing control structures.
 
 

if/else
 
 

if/else control structures will have the following style.

int main()
{
        long lGrade1, lGrade2;

        if(lGrade1 < lGrade2)
        {
                  //code goes here
        }
        else if(lGrade1 == lGrade2)
        {
                  //code goes here
        }
        else
        {
                  //code goes here
        }
}

The general rule is this for nested if statements

if( <expression )
{
        if( <expression ) //first nest
        {
                if( <expression ) //second nest
                {
                    //code goes here
                }
                else if( <expression ) //else for the second nest and a third nested if
                {
                    //code goes here
                }
                else
                {
                    //code goes here
                }
        }
        else
        {
             //code goes here
        }
}
 
 

Notice the indentation.  All code will be indented for three to five spaces.  This can typically be setup in any editor by using the tab key and setting the tab space to 3, 4 or 5 spaces.  Also all if blocks will have the { } braces.  I do not want to see code that looks like this

if( <expression )
    //program statement
else
    //program statement

Even if there is only one statement pertaining to the if or else condition always use the {} braces as described above.
 

Switch/Case
 
 

Switch cases only are used for Integer based values.  When comparing equality on a variable to more than one value it is more efficient to use a switch/case than an if/else control structure.  This will be explained further in class.  Assume I have a variable Called KeyCode and using the enumerations defined in the enumeration section for Key values we produce the following code fragment:
 
 

void ExampleSwitchCase(VirtualKey KeyCode)
{
    switch(KeyCode)
    {
            case VK_1:
            {
                //program statements go here
                 break;
            }
            case VK_2:
            {
                //program statements go here
                 break;
            }
            case VK_3:
            {
                //program statements go here
                 break;
            }
            case VK_4:
            case VK_5:
            {
                //program statements go here
                 break;
            }
            default:
            {
                //program statements go here
                 break;
            }
    }
}

All case statement will have a {} braces.  This is a good coding practice since defining a variable within the case statement will produce warnings or errors depending on the compiler so using scope indicators {} will eliminate this problem.  Also notice VK_4 and VK_5 are sequenced one after the other, this means that if KeyCode evaluates to VK_4 or VK_5 that code will be executed for it.  Also all case statements will have a default case whether you need one or not.  Finally all case statements will have a break.  Forgetting the break is a common programming error.

For Loop
 

The for loop is very flexible and because of this we will try to keep to a more strict syntax for program readability.

       Syntax:
                      1.   for(<section 1 ; <section 2; <section 3)
                                //a single statment
                      2.   for(<section 1 ; <section 2; <section 3)
                            {
                               //any number of statements
                            }

In form 1 this leads to common programming errors by assuming later all you have to do is add another statement and the loop will apply to that statment as well.  The begin end braces will make sure that this common error will not happen.  Always use form 2.  Form 2 is the desired form for constructing the for loop.  This form will guarantee that when you add statements later it will also apply to the added statment since they

are enclosed in braces.  Now lets break down each section in the for statment:

<section 1 : This section will be strictly reserved to initializing loop variable or variables.  Or whatever variable you are using to test for loop termination.

<section 2: Will be reserved for testing the loop variable for a stopping condition.  Make sure that the condition will be reached to avoid infinite loops.

<section 3: Will only be sued to adjust the loop variable to eventually reach the stopping condition.

Example:

         for(Counter = 0; Counter < 50; Counter++)
         {
              cout << "Counter =  " << Counter << endl;
         }

The semicolons separating each section is required.  Notice I did not do this:

         for(Counter = 0; Counter < 50; Counter++, cout << "Counter =  " << Counter << endl)
         {
         }

Even though the above is legal and should generate the same output as the first program it is hard to read.  Only place in each section what is required to initialize test and adjust the loop variable, NOTHING ELSE.

Now since newer version of compilers are coming out the scope of variables defined in the initialization section of the for loop would be only within the for loop or within the body of the function in which the for loop is defined in.  I believe the standard is to have the scope only pertain to the scope of the for.

        Example:
                    for(long Counter = 0; Counter < 50; Counter++)
                    {
                            cout << "Counter =  " << Counter << endl;
                    }
                    cout << Counter << endl; //for some compilers this is undefined symbol
                    for(long Counter = 0; Counter < 50; Counter++)
                    {
                            cout << "Counter =  " << Counter << endl;
                    }
 

Some compilers would treat the last statement as undefined symbol because they assumed that the scope of the variable was only within the scope of the for statement and once the for statement is exited then Counter no long exists.  The second for loop defines Counter again and for some compilers this is ok if the scope of Counter for the first loop was only for the loop and not the entire function.  If the scope was for the entire function then the Counter variable would be multiply defined.  To avoid this all together we will define our loop variables at the top of the scope.
 
 

int main()
{
        long Counter = 0;     //loop variable defined at top of scope

         for(Counter = 0; Counter < 50; Counter++)
         {
              cout << "Counter =  " << Counter << endl;
         }
         cout << Counter << endl;
         for(Counter = 0; Counter < 50; Counter++)
         {
              cout << "Counter =  " << Counter << endl;
         }

    return 0;
}
 

Now the above code has no problems with any compilers.

Indentation will be identical to the if/else when we next for loops

        for(Row = 0; Row < 50; Row++)
        {
                //statements
                for(Column = 0; Column < 50; Column++)
                {
                        //statements
                }
                //statements
        }

the next can go as deep as you would like.  In the above program the inside loop indicated by Column will be executed Row number of times which is 50 and the inside loop indicated by column will be executed Column number of times which is also 50.
 

While

While loops will have the following coding style:

    while( <expression )
    {
    }

The above will be used even if we have only one statement to execute.  Nesting while loops will have the same format as for loops and nested if statements.

    while( <expression )
    {
            while( <expression )
            {
                    while( <expression )
                    {
                            //and so on
                    }
            }
    }

Make sure all braces match up and you use proper indentation.
 

Do/While
 

do/while loops will abide by the following syntax

    do
    {
        //statements or statement
    } while( <expression );

I like to put the while on the same line as the last brace.  This will lwt you know that it is part of a do/while and not just a while statment.

nested loops will be the same as the previous sections

    do
    {
            do
            {
            } while ( <expression );

    } while( <expression );
 
 

Functions



This section will pertain to coding standards when working with functions.  In C++ we would like to keep the number of functions that exist in the program to a bare minimum or next to none.  C++ should be about objects and communicating between them and avoid the functional approach as much as possible.  This section will show you some coing standards that we will abide by in this course.

The length of the functions should allways fit inside an editor.  If your function stretches for more than 15 to 20 lines you probably are doing a little too much and need to create some additional functions.  Functions are used to enhance readability and to make your programs more modular and extendable.   Make sure your function does what it is designed to do and no more.  For example if you were to implement a square function it should not perform I/O and subtracions and divisions, it should just square a value and return it.
 

Function Documentaion
 
 

All functions will be documented.  At the top of each function you will have a comment that looks something like this:

/////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Name:                        Square
//
//  description:               The function will take an argument and return its square.
//
//  arguments:
//        double Value        This is a double precision value and will be squared and
//                                     the result returned back to the caller.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////
inline double Square(double Value)
{
    return (Value * Value);
}
 

I will allow comments inside your function.  These comments will not be long they will be short and concise.

istream& ScanInput(istream& InputStream)
{
    char CurrentChar;

    while( (CurrentChar = cin.get())!=EOF) //get cahracter and test for EOF. Short and concise
    {
        // this comment will be and example of maybe having one way way way
        // too long.  Just think if I used comments this large after every couple of  statments.  The actual code
        // can become unreadable.
        switch(CurrentChar)
        {
        // this comment will be and example of maybe having one way way way
        // too long.  Just think if I used comments this large after every couple of  statments.  The actual code
        // can become unreadable.
            case '%': //handle hex character indicator. Short and concise comment
            {
                break;
            }
        // this comment will be and example of maybe having one way way way
        // too long.  Just think if I used comments this large after every couple of  statments.  The actual code
        // can become unreadable.
            case '&': //handle name value separator. Short and concise
            {
                break;
            }
        // this comment will be and example of maybe having one way way way
        // too long.  Just think if I used comments this large after every couple of  statments.  The actual code
        // can become unreadable.
            default:
            {
            }
        }
    }

    return InputStream;
}

Notice how the larger comments that extend multiple lines clutter up the function.  Too many comments can be bad.  Make sure that if you comment within the function you use short and concise comments as seen to the right of the while statement and to the right of a couple of case statements as seen in bold face.  Put the larger comments in the description section of the documentation template that goes above the function.  Look at the same function with just the short and concise statements.

/////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Name:                        ScanInput
//
//  description:               The function will take an input stream and parse it and.
//                                    look for special characters.  These characters will be
//                                    converted to their decoded values.  The % tells us that the
//                                    next two characters will correspond to a hex number.  The
//                                    larger set of comments that we saw above can go here in the
//                                    description section.  If you need to do detailed explanation
//                                    of a complicated or confusing step in you function and need
//                                    to have several lines to explain it then do it here
//
//  arguments:
//       istream& InputStream
//                    This is a double precision value and will be squared and
//                     the result returned back to the caller.
//
//      Type Name
//                    More comments here if the argument existed
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
istream& ScanInput(istream& InputStream)
{
    char CurrentChar;

    while( (CurrentChar = cin.get())!=EOF) //get cahracter and test for EOF. Short and concise
    {
        switch(CurrentChar)
        {
            case '%': //handle hex character indicator. Short and concise comment
            {
                break;
            }
            case '&': //handle name value separator. Short and concise
            {
                break;
            }
            default://Pass through all other characters
            {
            }
        }
    }

    return InputStream;
}
 

Function Naming

Coming up with a function name will adhere to the same rules as a variable name, where the first character of each word is capitalized.

void MyTestFunction()
{

}

Each word in the function is capitalized.  Make the name descriptive and concise.  There is no need to create a 25 character function name.
 

Function Arguments
 

Arguments to the function will consist of a name that is descriptive.  Just by looking at the name of the function and the name of the arguments a user should know exactly what the function is going to do.

void Output(string Data)
{

}

versus

void O(string D)
{

}

Assume both function do the same think.  With just looking at the name of the function and the argumets can you tell me which one has a better description?  I hope you chose the first form,  Output(string Data).  The name of the function tells us it outputs something and the argument tells us it corresponds to some data string.  For multiple arguments separate each with a comma and a space.

void DemostrationFunc(long Argument1, long Argument2, double Argument3)
{

}

and not like this

void DemostrationFunc(long Argument1,long Argument2,double Argument3)
{

}

In the second form the arguments are jumbled close together and are hard to read use the first form when spacing out arguments.
 

Classes

/////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Name:                        class MyClass
//
//  description:               Give a general description of what the class does.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////

class MyClass
{

public:

MyClass();

:

:

:

protected: void ProtectedFunction();

:

:

:

private: void PrivateFunction();

:

:

:

};

I want all documentation of the member functions to be placed in the source file. The dcumentation will abide by the same rule as the function docs.

/////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Name:                        ProectedFunction
//
//  description:               Performs a nice binary search.
//
//  arguments:
//      Type Name
//                    More comments here if the argument existed
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////

void MyClass::ProtectedFunction()

{

}