C++ Coding Standard

Brett Slocum

 

 

 

 

2/13/97

C++ Coding Standards

 

  1. Introduction

    This documentation describes coding standards using C/C++ in our environment. As with most standards and guidelines, this document is not fixed in concrete, but it is not a suggestion either. Programmers are required to follow these recommendatio

    As such, the standards are not intended to create obstacles or encourage bureaucracy. Consequently, if programmers see revisions need to be made, it is their responsibility to review changes with the architect team so they can be incorporated in the s

    If a particular situation arises where a good case can be made to violate the standards, discuss it with the architecture team and fully document the variance.

  2. File Organization

    C++ source files should have a .cpp extension. Each source file should always have a header file with same name and a .h extension.

    File names should be 31 characters or less. No embedded spaces should be used in file names. The name of the file should be the name of the class contained in the file without the leading "C".

    Examples:

    Valid filenames for the given classes:

    Class Source File Header File
    CCPRMolecule CPRMolecule.cpp CPRMolecule.h
    CCCAMyClass CCAMyClass.cpp CCAMyClass.h
    CCPRAtomRevision CPRAtomRevision.cpp CPRAtomRevision.h

    There should be only one primary class definition per file.

    1. Header Files
      1. Comment Block The comment block in a header file describing the purpose and maintenance history of the file should follow the template below:
        #ifndef CLASSNAME_H
        #define CLASSNAME_H
        
        ///////////////////////////////////////////////////////////////////////////////
        //
        // $Header:  $
        //
        // NAME:  className
        //
        // BASE  CLASSES: none
        //  
        // PURPOSE:  purpose description
        //
        // AUTHOR:  Who created this originally
        //
        //  COPYRIGHT NOTICE:
        //
        //      (C) Residential Funding Corporation
        //      Created in 1997 as an unpublished copyright work.  All rights reserved.
        //      This document and the information it contains is confidential and
        //      proprietary to Residential Funding Corporation.  Hence, it may not be 
        //      used, copied, reproduced, transmitted, or stored in any form or by any 
        //      means, electronic, recording, photocopying, mechanical or otherwise, 
        //      without the prior written permission of Residential Funding 
        //      Corporation.
        //
        //  REVISION HISTORY:
        // $Log:      $
        ///////////////////////////////////////////////////////////////////////////////
        
        // Includes
        
        // Constants
        
        // Types and Classes
        
        // ... rest of the file goes here
        
        #endif // CLASSNAME_H
        
        
      2. Allowed Contents

Header files may contain:

  1. Type definitions
  2. Templates
  3. Function declarations
  4. Inline function definitions
  5. External data declarations
  6. Constant definitions
  7. Enumeration types
  8. Name declarations
  9. Include statements
  10. Comments

Examples:

Lexical Element

Example of Code

Notes/Comments

Type Definition



typedef float REAL;

Define a type REAL which is a floating-point number

Template



List<Atom> *resatomlist;

Example of class data using templates

Function Declaration


Atom *GetAtom( Atom *atom);

A class member function declaration

Inline Function Definition


inline char* CResidue::GetResidueName() {return residuename;}

An access function for class Residue

External Data Declaration



extern CString sName;
 

Constant Definition


const float pi = 3.14159;

The keyword const redefines the word pi to mean a floating-point number whose value is set to 3.14159

Enumeration


enum EColor(red, green, blue}; EColor eColor;

Thus, we could specify:

eColor=green;
to set eColor

Name declaration

   

Include statement


#include "Molecule.h"


The quotes indicate a user-defined header file is to be included.

Comment


// This is a comment line

The C++ comment characters (//) should be used in preference over the old style (/* and */) comment characters.

They may not contain:

  1. Ordinary function definitions
  2. Variable definitions
  3. Constant aggregate definitions
  4. External references to global variables
  1. Guard Code

    Header files will define and test a preprocessor variable preventing multiple inclusion of that header file in the same translation unit:

    #ifndef RESIDUE_H
    #define RESIDUE_H
    
    ...rest of code...
    
    #endif
    
  2. Include Statements

Each header file will contain #include statements for all header files on which it depends:



#include "header_file.h"



or



#include <header_file.h>

for default (compiler-default) header files. Do not include pathnames in the #include statement. Use the Tools/Options menu in Developer Studio to add directories to the search path.

Do not create order dependencies among header files for classes that reference each other. Specify forward declarations for each class to avoid this situation.

Do not group forward references into a single header file. While this has some organization appeal, it results in superfluous class declarations.

  1. Source Files
    1. Comment Block The comment block in a source file describing the purpose and maintenance history of the file should follow the template below:
      ///////////////////////////////////////////////////////////////////////////////
      //
      // $Header:  $
      //
      // NAME:  className
      //
      // BASE  CLASSES: none
      //  
      // PURPOSE:  purpose description
      //
      // AUTHOR:  Who created this originally
      //
      //  COPYRIGHT NOTICE:
      //
      //      (C) Residential Funding Corporation
      //      Created in 1997 as an unpublished copyright work.  All rights reserved.
      //      This document and the information it contains is confidential and
      //      proprietary to Residential Funding Corporation.  Hence, it may not be 
      //      used, copied, reproduced, transmitted, or stored in any form or by any 
      //      means, electronic, recording, photocopying, mechanical or otherwise, 
      //      without the prior written permission of Residential Funding 
      //      Corporation.
      //
      //  REVISION HISTORY:
      // $Log:      $
      //
      ///////////////////////////////////////////////////////////////////////////////
      
      ///////////////////////////////////////////////////////////////////////////////
      //  Includes 
      
      
      // Constants
      
      
      // Externals
      
      
      // Types and Classes
      
      
      // Variables
      
      
      // Member Functions
      
    2. Include Statements Only those header files needed directly by the source file should be included. For Visual C++, StdAfx.h should be included first for the proper creation of precompiled headers. No other code, except for comments can precede the StdAfx.h include.
    3. Function Comments

Each function (excluding Get and Set access functions and Operators) must have a header that includes the following elements:

NAME
Name of the function
DESCRIPTION
Describes the purpose, usage and other important information concerning this function. Any precondition should be specified here. Note: Do not describe how the function does its job. That's what the source code is for. One doesn't wa
PARAMETERS
A list of each of the parameter names and a brief description of that parameter. The name of the parameter should be followed by one of three
RETURN
The type returned and a brief description of that object. Include any requirement for this return type (e.g. must release the memory).
SIDE EFFECTS
Anything that might happen that would not normally be expected by a user.

Example:

///////////////////////////////////////////////////////////////////////////////
//
// NAME:  open
//
// DESCRIPTION:  opens the specific file.
//
// PARAMETERS:  path(0)  - full pathname for the file to be opened
//
// RETURN:  CStatus    - Boolean, indicates success or failure
//
// SIDE  EFFECTS: none
//
///////////////////////////////////////////////////////////////////////////////

BOOL CStatus open(char *path)
{
     function body….
}

  1. Source Code Style

      
  1. Naming Conventions

Do not rely on upper and lower case differences to yield unique names.
  1. Word separators

Separate words in identifiers by capitals, not underscores.

Variable names should be prefixed by Hungarian notation. More than one prefix may apply (e.g. a pointer to an exception object could be named pxPricingException). Regular prefixes include:


      

Prefix

Data Type

a

array

b

BOOL

by

unsigned char (BYTE or UCHAR)

c

char

C

class

d

double

dw

DWORD (unsigned long)

e

enum variable

E

enumerated type

f

float

h

Windows handle

i

int or short

l

long

m_

class member variable

n

int

p

pointer

s

CString

sz

zero-terminated char string

u

unsigned int

v

void

w

WORD (unsigned word)

x

C++ exception object



           

Names of enumerated types and classes should begin with an uppercase letter (either E or C, respectively), whereas names of variables and constants should begin with a lowercase letter. Use the Windows standard of starting functions with an upperca
Names should indicate the meaning of the variables, rather than their type. Names should be descriptive and use complete words. Avoid the use of initial or trailing underscores. Use multiple words – but use them carefully. It can be hard to remember
Similarly:
Correct Incorrect
szDateDue szDueDate
szNameFirst szFirstName
eColorRed eRedColor
iVolumeMax iMaxVolume
bStatusEnabled bEnabledStatus



Naming variables this way means that related variables tend to sort together, making cross-reference listings more useful.

      
  1. Indent size

Use four spaces. Do not use tabs because different editors and printers deal with tabs differently. These parameters can be set in the Tools/Options menu of Visual C++.

Braces shall follow an indented block style in which opening and closing braces are each placed on separate line lined up vertically with the control statement. The body of the code within braces is indented by one indent level.
Example
:
while (iLoopingCount)
{
    doSomeThing();
}


Line length should not exceed eighty characters.

Do not use multiple statements per line.
Example
:
// Incorrect

a = b; c++; d = GetMax();

// Correct

a = b;
c++;
d = GetMax();



Put class names against the margin.
Example
:
WORD
class::func()
{
    doSomeThing();
}



Use lots of spaces, except around ‘.' or ‘->' or between unary operators and operands.
Pointer modifiers "*" and reference modifiers "&" in declarations are grouped with the type, not the variable. Overloaded operators immediately follow the key word operator, with no intervening white space.
Example
:
char* p = "hello";

Complex operator+ (const Complex& op1, const Complex& op2);



Comments should be used liberally to explain what code is doing and why, but should not duplicate information readily discernable in the code itself. Comments are meant to be read by others, so liberal use of white space and blank lines will incre
Use C++-style comments (i.e. // ), except where commenting out part of the middle of a line (such as unused formal parameters). There should be one space between the double slash and the start of the comment text.
Example:
Unsigned draw_rect(unsigned wWidth, unsigned wHeight /*, unsigned wDepth */)


  1. Block Comments

Block comments should have blank lines above and below. A block comment is a comment containing two or more lines.
Examples
:
// This is a C++ block comment.
// It has two lines in it.

// This is a single-line comment



End of line comments are small annotation tacked on the end of a line of code. They are focused on one or a very line of codes where block comments refer to larger sections of code.
Example
:
IEmployeeCur = iEmployeeCur + 1;       // Keep the index pointer
                                       // synchronized for OLE clients

      

Do not use #define to declare constant values. Const or enum should be used instead.
Example
:
const WORD wMode;


Use enumeration for a set of related constants rather than declaring them separately.
Example
:
// Incorrect
const unsigned int iCOLOR_RED = 0;
const unsigned int iCOLOR_GREEN = 1;
const unsigned int iCOLOR_BLUE = 2;

// Correct
enum EColor {eRed, eGreen, eBlue};



Do not repeat const declarations in both source and header files. If it is declared in the header file, it is meant for other modules to share. If it is declared in the source file, only that module is meant to use it.
Use constant variables, instead of literal constants, especially if used in more than one place.
Example
:
// Incorrect
int iID = 1000;

// Correct
In the .CPP file:
int iID = iStartingID;

In the .h file:
const int iStartingID =        1000;






Limit the scope of variables as much as possible.
Each variable is to be declared in a separate declaration statement.
Examples
:
// Incorrect
CString sFilename, &rsDirectory;

// Correct
CString sFilename;
CString& rsDirectory;



Define variables close to where they will be used.
Always initialize variables. Declare and initialize variables no earlier than the point at which their initialization values are known.
Avoid local variable names that are identical to the names of variables with greater scope.
Beware of the variable's scope. The variable will often remain in existence longer than originally anticipated.
  1. Global variable definitions

Global variables are strongly discouraged.
Do not use global variables that only have module (throughout the current source file only) scope.

Use struct when there are no private or protected member data and no member functions (including constructors and destructors). In other words, use struct for public data structures. Use class in all other cases.
Member data and functions should be declared in the following order: public members, protected members, and private members. Always use the access keywords public, protected, and private.
  1. Encapsulation

Member data in a class should be declared private, not protected or public. This is to adhere to the object-oriented design principle of data encapsulation. If other classes need access to member data, provide get and
Hide member functions that are not required for the external interface using the private or protected keyword.
Localize and hide design decisions that may change.

When using inheritance, specify public for each parent class.
Example
:
class myClass
{
    // ….
}

class derivedClass : public myClass
{
    // ….
}



In Visual C++, classes that have no other parent class should be derived from CObject. This allows these classes to be part of templated collection classes.
Avoid multiple inheritance.

Keep function length to less than two pages. One page is better. Long functions are more difficult to understand and maintain.
Do not use variable length argument lists (similar to printf).
Large function parameters should be passed by reference, not by value. If the function is not changing the value of a large parameter, declare that parameter const. Small parameters that won't be changed by the function can be passed by value.
Whenever an address is returned from a member function, it should be returned as a const pointer or a const reference, unless you want the user to be able to change the contents of what the pointer de-references.
  1. Inline Functions

Inline functions should not be used, unless performance is known to be a problem. The exception to this rule is access functions, which should be inline, but not within the body of the class.
Constructors and destructors should not be inline.
Inline functions should be three lines long or less.
Example
:
// Incorrect

class CPriority
{
    public:
        int        CPriority() // should not use inline here
        {
            doSomething();
        };
   int getx();
   private:
       int   x; 
};

int CPriority::getx() // inline should be used here
{
    return(x);
}

// correct

class CPriority
{
     public:
        int        CPriority(); // constructor should not use inline
        int getx();

     private:
         int   x; 
};

// constructor
int CPriority::CPriority()
{
    doSomeThing();
}


inline int CPriority::getx () // get function can use inline
{
    return(x);
}



A member function that does not affect the state of an object (its member data) is to be declared const. Member functions declared as const may not modify member data and are the only functions that may be invoked on const obj

Initialize member data in the class constructor. Pointers should be set to 0 in the constructor and deleted in the destructor.
Constructors should use initialization, not assignment, to set member data, if possible.
Example
:
// Incorrect

Catom::Catom(int iAtNum, float fAtWt)
{
    m_iAtomicNumber = iAtNum;
    m_fAtomicWeight = fAtWt;
}

// Correct

Catom::Catom(int iAtNum, float fAtWt) : m_iAtomicNumber(iAtNum), 
 m_fAtomicWeight(fAtWt)
{
    ;    // Empty
}


A class that uses the new keyword to allocate objects managed by the class must define a copy constructor. This is to avoid surprises when an object is initialized using an object of the same type. If an object manages the allocation an
Example
:
//  Incorrect

class String
{
    public:
        String( const char* cp = "");    // constructor
        ~String();                       // destructor
    private:
         char *sp;
};

String::String(const char* cp) : sp ( new char[strlen(cp)] )     // constructor
{
    strcpy(sp, cp);
}

String::~String()                            // destructor
{
    delete sp;
}

void 
main()
{
    String w1;
    String w2 = w1;

    // Warning:  the destructor for w1::sp will be called twice:
    // first when w1 is destroyed;  again, when w2 is destroyed.
}

//  Correct

class String
{
    public:
        String( const char* cp = "" );    // constructor
        String( const String& sp );       // copy constructor    
        ~String();                        // destructor
        // …
     private:
         char *sp;
         // …
};

String::String( const String& stringA ) : sp( new char[strlen(stringA.sp)] )
{
    strcpy ( sp, stringA.sp );
}

String::~String()                            // destructor
{
    delete sp;
}

void 
main()
{
    String w1;
    String w2 = w1;     // SAFE COPY:   String::String( const String& ) called.
}



All classes that are used as base classes and have virtual functions, must define a virtual destructor.
Avoid the use of global objects in constructors and destructors.

Use operator overloading sparingly and in a uniform manner. One disadvantage in overloading operators is that it is easy to misunderstand the meaning of an overloaded operator

Use friend functions sparingly. Friends offer an orderly way of getting around data encapsulation for a class. A friend class can be advantageously used to provide functions that require data that is not normally needed by the class

A break statement must always terminate the code following a case label.
A switch statement must always contain a default branch that handles unexpected cases.
If testing the value of a single variable, use a switch statement instead of an if statement.
The flow control statements if, while, for and do should be followed by a block, even if it is empty or contains a single line.
Example
:
//Incorrect

while ( !bSomething ) ;
for ( i = 0; i < 10; i++ )
    cout << aSomeArray[I];

//Correct

while ( !bSomething )
{
    ;    // Empty
}

for ( i = 0; i < 10; i++ )
{
    cout << aSomeArray[I];
}



Do not embed assignment statements into flow control statements.
Example
:
// Incorrect

if ( bFlag = GetStatusWrite() )
{
    ...
}

// Correct

bFlag = GetStatusWrite();
if ( bFlag )
{
    ...
}


Never use goto. Goto breaks the control flow and can lead to code that is difficult to comprehend.
Avoid the use of continue. Continue can be used to exit from loops. However, code may be more comprehensible by using an else clause instead.
  1. Boolean Tests

Only use if (something) and if (!something) when something is a BOOL value. If it is a multi-valued variable or a pointer, test for equality with 0.
Examples
:
if (!strcmp( myString, "value" )) // Bad
if (strcmp( myString, "value" ) == 0)  // Good



Minimize the use of return, break, continue and goto statements which override normal control statement structure. However, each of these statements has a place - use them when the code would be significantly more convo

      
  1. Debugging

Test the input parameters of a member function for valid data using the assert function.

Catch exceptions thrown by MFC functions. Use a try-catch block around calls to these functions.
Example
:
CRecordSet clPriceData;

try
{
    clPriceData.Open();
}
catch (CDBException* pxOpen)
{
    pxOpen.
}




Avoid unions, as they defeat strong type-checking and are very difficult to verify in a debugger.

Do not use realloc. Malloc, calloc, and free should be avoided; the operators new and delete should be used instead.
Always use delete whenever memory was allocated by the new operator. In order to help eliminate the problem of accessing memory that has been freed, the pointer must be assigned to 0 after the pointer has been deleted. Note: there are in

Use the C++-style iostream class, not printf, fprintf, or other C-style input/output routines.

Use the BOOL and CString classes provided by MFC, not int (for boolean responses) or char* types from C.
Use MFC classes where appropriate.

The C++ language definition unequivocally defines a pointer value of 0 (zero), or any expression that evaluates to zero, as a null pointer. Stroustrup writes, "A constant expression that evaluates to zero is converted to a pointer, commonly c

      
  1. C++ Coding Standard, Apertus Enterprise Systems Group, January 1997.
  2. C/C++ Programming Guide, Hassan Kaganda, Deluxe Corporation, January 1997.
  3. Programming in C++, Rules and Recommendations, Mats Henricson and Erik Nyquist, Ellemtel Telecommunications Systems Laboratories, April 1992.







  1. Glossary





abstract base class
A class from which no objects may be created; it is only used as a base class for the derivation of other classes. A class is abstract if it includes at least one pure virtual member function.
access function

A function that set or returns the value of member data.
accessor

See access function.
catch clause

The exception handler executed when an exception is raised. The definition of an exception handler begins with the keyword catch.
class

A user-defined data type that consists of data elements and functions that operate on that data. In C++, this may be declared as a class; it may also be declared as a struct or a union.
class template

Definition of a family of classes. A new class may be created from a class template by providing values for a number of arguments. These values may be names of types or constant expressions.
compilation unit

The source code (after preprocessing) that is submitted to a compiler for compilation.
constant member function

A function that may not modify member data.
constructor

A function that initializes an object when it is created.
copy constructor

A constructor in which the first argument is a reference to an object that has the same type as the object to be initialized. A copy constructor is used to initialize an object to the same value as another object of the same type.
default constructor

A constructor that needs no arguments. The compiler often automatically generates a default constructor for a class, if the programmer does not define one.
destructor

A function called when an object is destroyed.

enumeration
type
An explicitly declared set of symbolic integer constants. In C++ it is declared as an enum.
exception

A run-time program anomaly that is detected in a function or member function. Exception handling provides for the uniform management of exceptions. When an exception is detected, it is thrown (using a throw expression) to the exception handler.
forwarding function

A function that does nothing more than call another function.
function template

Definition of a family of functions. A new function may be created from a function template by providing values for a number of arguments. These values may be names of types or constant expressions.
identifier

A name that is used to refer to a variable, constant, function or type in C++. When necessary, an identifier may have an internal structure that consists of a prefix, a name, and a suffix (in that order).
inline function

A function declared with the inline keyword that gets directly replaced by its statements at compile time. Also, any member functions declared within the body of a class are automatically inline.

iterator

An object which, when invoked, returns the next object from a collection of objects.
macro

A name for a text string which is defined in a #define statement. When this name appears in source code, the compiler replaces it with the defined text string.
member data

Data identifiers defined within a class.
member
function

Functions defined within a class.
overloaded function

A function name that is used for two or more functions or member functions having different types.
overridden member function

A member function in a base class that is redefined in a derived class. Such a member function is declared virtual.
predefined data type

A type defined in the C++ language, such as int or float.
private member

The member data and member functions of a class that are only accessible within the class.
protected member

The member data and member functions of a class that are only accessible within the class and its derived classes.
public member

The member data and member functions of a class that are accessible everywhere.
pure virtual function

A member function for which no definition is provided. Pure virtual functions are specified in abstract base classes and must be defined (overridden) in derived classes.
reference

An identifier that refers to another identifer directly. In C++, the ambersand (&) is used immediately after the data type to indicate that the declared variable, constant, or function argument is a reference.
scope
The context of a program in which an identifier exists.
structure

A user-defined type for which only public data is specified.
typedef

A typedef declaration in C++ specifies another name for a data type.
user-defined data type

A type that is defined by a programmer in a class, struct, union, enum, or typedef definition or as an instantiation of a class template. [an error occurred while processing this directive]