this page is a revisited mirror under construction (!)

http://www.possibility.com/Cpp/CppCodingStandard.html
original page (approx. 128 kb)
http://www.ulb.ac.be/esp/ip-Links/Java/joodcs
return to Java OO design home page

C++ Coding Standard

Last Modified: Jun 3 1997

mailto:tmh@possibility.com / My Home Page

Using this Standard. If you want to make a local copy of this standard and use it as your own you are perfectly free to do so. That's why I made it!. If you find any errors or make any improvements please email me the changes so I can merge them in.

Table of Contents


Introduction

Standardization is Imporant

It helps if the standard annoys everyone in some way so everyone feels they are on the same playing field. The proposal here has evolved over many projects, many companies, and literally a total of many weeks spent arguing. It is no particular person's style and is certainly open to local amendments.

Good Points

When a project tries to adhere to common standards a few good things happen:

Bad Points

Now the bad:

Discussion

The experience of many projects leads to the conclusion that using coding standards makes the project go smoother. Are standards necessary for success? Of course not. But they help, and we need all the help we can get! Be honest, most arguments against a particular standard come from the ego. Few decisions in a reasonable standard really can be said to be technically deficient, just matters of taste. So be flexible, control the ego a bit, and remember any project is fundamentally a team effort.

Interpretation

Conventions

The use of the word "shall" in this document requires that any project using this document must comply with the stated standard.

The use of the word "should" directs projects in tailoring a project-specific standard, in that the project must include, exclude, or tailor the requirement, as appropriate.

The use of the word "may" is similar to "should", in that it designates optional requirements.

Terminology

For the sake of simplicity, the use of the word "compiler" means compiler or translator.

"C++ Coding Standard" refers to this document whereas "C++ ANSI Standard" refers to the proposed C++ language definition.

The term "method" means function. Usually, a method is a function that is a member of a class.

Standards Enforcement

First, any serious concerns about the standard should be brought up and worked out within the group. Maybe the standard is not quite appropriate for your situation, it may have over looked important issues, or maybe someone in power vehemently disagrees with certain issues :-)

In any case, once finalized hopefully people will play the adult and understand that this standard is reasonable, and has been found reasonable by many other programmers, and therefor is worthy of being followed even with personal reservations.

Failing willing cooperation it can be made a requirement that this standard must be followed to pass a code inspection.

Failing that the only solution is a massive tickling party on the offending party.

Accepting an Idea

  1. It's impossible.
  2. Maybe it's possible, but it's weak and uninteresting.
  3. It is true and I told you so.
  4. I thought of it first.
  5. How could it be otherwise.
If you come to objects with a negative preconception please keep an open mind. You may still conclude objects are bunk, but there's a road you must follow to accept something different, allow yourself to travel it for a while.

6 Phases of a Project

  1. Enthusiasm
  2. Disillusionment
  3. Panic
  4. A Search for the Guilty
  5. The Punishment of the Innocent
  6. Praise and Honor for the Non-Participants

Flow Chart for Project Decision Making

                       +---------+
                       |  START  | 
                       +---------+
                            |
                            V            
            YES       +------------+      NO
      +---------------|  DOES THE  |---------------+               
      |               | DAMN THING |               |
      V               |    WORK?   |               V    
+------------+        +------------+        +--------------+  NO
| DON'T FUCK |                              | DID YOU FUCK |-----+
| WITH IT    |                              |   WITH IT?   |     |
+------------+                              +--------------+     |
      |                                            |             |
      |                                            | YES         |
      |                                            V             |
      |  +------+     +-------------+       +---------------+    |
      |  | HIDE |  NO | DOES ANYONE |<------| YOU DUMBSHIT! |    |                 
      |  |  IT  |<----|    KNOW?    |       +---------------+    |
      |  +------+     +-------------+                            |
      |      |               |                                   |
      |      |               V                                   |
      |      |        +-------------+       +-------------+      |
      |      |        |   YOU POOR  |  YES  |  WILL YOU   |      |     
      |      |        |   BASTARD   |<------| CATCH HELL? |<-----+
      |      |        +-------------+       +-------------+
      |      |               |                     |
      |      |               |                     | NO
      |      |               V                     V
      |      V        +-------------+       +------------+ 
      +-------------->|    STOP     |<------| SHITCAN IT |
                      +-------------+       +------------+
      
                              


Names

Make Names Fit

Names are the heart of programming. In the past people believed knowing someone's true name gave them magical power over that person. If you can think up the true name for something you give yourself and the people coming after power over the code. Don't laugh!

A name is the result of a long deep thought process about the ecology it lives in. Only a programmer who understand the system as a whole can create a name that "fits" with the system. If the name is appropriate everthing fits together naturually, relationships are clear, meaning is derivable, and reasoning from common human expectations works as expected.

If you find all your names could be Thing and DoIt then you should probably revisit your design.

Class Names

Method and Function Names

No All Upper Case Abbreviations

Justification

Example

   class FluidOz             // NOT FluidOZ
   class NetworkAbcKey       // NOT NetworkABCKey


Class Names

Justification

Example

   class NameOneTwo
  
   class Name


Class Library Names

Example

John Johnsons complete data structure library could use JJ as a prefix, so classes would be:
   class JjLinkList
   {
   }


Method Names

Justification

Example

   class NameOneTwo
   {
   public:
      int                   DoIt();
      void                  HandleError();
   }


Class Attribute Names

Justification

Example

   class NameOneTwo
   {
   public:
      int                   VarAbc();
      int                   ErrorNumber();
   private:
      int                   mVarAbc;
      int                   mErrorNumber;
      String*               mpName;
   }


Method Argument Names

Justification

Example

   class NameOneTwo
   {
   public:
      int                   StartYourEngines(
                               Engine& someEngine, 
                               Engine& anotherEngine);
   }


Variable Names on the Stack

Justification

Example

   int
   NameOneTwo::HandleError(int errorNumber)
   {
      int            error= OsErr();
      Time           time_of_error;
      ErrorProcessor error_processor;
   }


Pointer Variables

Justification

Example

  String* pName= new String;


Reference Variables

Justification

Example

   class Test
   {
   public:
      void               DoSomething(StatusInfo& rStatus);

      StatusInfo&        rStatus():
      const StatusInfo&  Status() const;

   private:
      StatusInfo&        mrStatus;
   }


Global Variables

Justification

Example

    Logger  gLog;
    Logger* gpLog;


Global Constants

Justification

It's tradition for global constants to named this way. You must be careful to not conflict with other global #defines and enum lables.

Example

    const int A_GLOBAL_CONSTANT= 5;


Static Variables

Justification

Example

   class Test
   {
   public:
   private:
      static StatusInfo msStatus;
   }


Type Names

Justification

Example

   typedef uint16  ModuleType;
   typedef uint32  SystemType;


#define and Macro Names

Justification

This makes it very clear that the value is not alterable and in the case of macros, makes it clear that you are using a construct that requires care.

Some subtle errors can occur when macro names and enum labels use the same name.

Example

#define MAX(a,b) blah
#define IS_ERR(err) blah


C Function Names

Justification

Example

   int
   some_bloody_function()
   {
   }


Enum Names

Labels All Upper Case with '_' Word Separators

This is the standard rule for enum labels.

Example

   enum PinStateType
   {
      PIN_OFF,
      PIN_ON
   }

Enums as Constants without Class Scoping

Sometimes people use enums as constants. When an enum is not embedded in a class make sure you use some sort of differentiating name before the label so as to prevent name clashes.

Example

   enum PinStateType            If PIN was not prepended a conflict 
   {                            would occur as OFF and ON are probably
      PIN_OFF,                  already defined.
      PIN_ON
   };

Enums with Class Scoping

Just name the enum items what you wish and always qualify with the class name: Aclass::PIN_OFF.

Make a Label for an Error State

It's often useful to be able to say an enum is not in any of its valid states. Make a label for an uninitialized or error state. Make it the first label if possible.

Example

enum { STATE_ERR,  STATE_OPEN, STATE_RUNNING, STATE_DYING};


Error Return Check Policy


Required Methods for a Class

To be good citizens almost all classes should implement the following methods:

Justification

Example

The default class template with all required methods.


Braces {} Policy

Of the three major brace placement strategies two are acceptable, with the first one listed being preferable:

Justification


Indentation/Tabs/Space Policy

Justification

Example

   void
   func()
   {
      if (something bad)
      {
         if (another thing bad)
         {
            while (more input)
            {
            }
         }
      }
   }


Parens () with Key Words and Functions Policy

Justification

Example


    if (condition)
    {
    }

    while (condition)
    {
    }

   strcpy(s, s1);

   return 1;


File Header

// NAME: 
//   XX -
//
// SYNOPSIS:
// DESCRIPTION:
// EXAMPLES:
// FILES:
// BUGS:
// SEE ALSO:
// TYPE:
///X///////////////////////X////////////////////X/////////////////////////////
The above is a general file header specifying a fairly standard man page style. Each different file type will fillout the header differently and will set the TYPE to the correct file type.

If your development system supports embedding HTML in comments then do so. Using HTML is especially useful for the SEE ALSO section.

Each file type will also have its own comment syntax. The example above is for C++.

C Comment Syntax

/* NAME: 
 *   XX -
 *
 * SYNOPSIS:
 * DESCRIPTION:
 * EXAMPLES:
 * FILES:
 * BUGS:
 * SEE ALSO:
 * TYPE:
 **X***********************X********************X****************************/

Scripts Using # for Comments

# NAME: 
#   XX -
#
# SYNOPSIS:
# DESCRIPTION:
# EXAMPLES:
# FILES:
# BUGS:
# SEE ALSO:
# TYPE:
#//X///////////////////////X////////////////////X/////////////////////////////

TYPE

A number of different file types are supported:

NAME

NAME is a summary statement for the file. XX is the name of the class, program, library, or whatever depending on the file type. It will be pulled out and put in various lists so please make it descriptive. NAME is also the keyword that tells a robot to parse the file. NAME must be on the first or second line of the file.

SYNPOSIS

The contents of a synopsis depend on the file type.

C++-CLASS and C++-BASE_CLASS

Synopsis should specify which libraries and header files needed to compile and use this class. If your documentation system doesn't automatically extract the public interface to a class then a class's interface should be explained under synopsis.

PROGRAM

List a programs usage.

LIBRARY

List all the elements of the library. Hypertext links are really useful here.

SUBSYSTEM

List all subsystem elements.

DESCRIPTION

The discription should go indepth about whatever is being represented. This section can be divided into subsections using a subtitle:
// DESCRIPTION
//   text
//
// A Subsection
//   text
// 
// Another Subsection

Space Markers

The class comment block has the following line:
///X///////////////////////X///////////////////////////////////////////////////
If any line is longer than this line then the line should be broken into parts.

This line also acts as a rule marking preferred indentation. The first X marks where a method's type should start. The second X marks where the method name should start. The third X is where one liner comments should start.

Make New Sections as Needed

As the section list in the header is not comprehensive you may add new sections as needed.


RCS Keywords, Change Log, and History Policy

When using RCS directly this policy must change, but when using other source code control systems like CVS that support RCS style keywords:

Justification


Class Layout

A common class layout is critical from a code comprehension point of view and for automatically generating documentation. Go here for more information on how comment blocks are used in system documentation. See file header for details on how to fill out the header.

Please use the following template when creating a new class. All you have to do is replace all XX blocks with your class name and you are ready to go.

// NAME: 
//   XX -
//
// SYNOPSIS:
// DESCRIPTION:
// EXAMPLES:
// FILES:
// BUGS:
// SEE ALSO:
// TYPE: C++-CLASS 
///X///////////////////////X////////////////////X/////////////////////////////

#ifndef _XX_h_
#define _XX_h_

// SYSTEM INCLUDES
//

// PROJECT INCLUDES
//

// LOCAL INCLUDES
//

// FORWARD REFERENCES
//


class XX
{
public:
// LIFECYCLE

   XX();
   XX(const XX&);                                // copy constructor
   ~XX();

// OPERATORS

   XX&                     operator=(XX&);       // assignment operator

// OPERATIONS                       
// ACCESS
// INQUIRY

protected:
private:
};

// INLINE METHODS
//

// EXTERNAL REFERENCES
//

#endif  // _XX_h_

Required Methods Placeholders

The template has placeholders for required methods . You can delete them or implement them.

Ordering is: public, protected, private

Notice that the public interface is placed first in the class, protected next, and private last. The reasons are: It makes sense then to have the interface first. Placing implementation, the private section, first is a historical accident as the first examples used the private first layout. Over time emphasis as switched deemphasizing a class's interface over implementation details.

LIFECYCLE

The life cycle section is for methods that control the life cycle of an object. Typically these methods include constructors, destructors, and state machine methods.

OPERATORS

Place all operators in this section.

OPERATIONS

Place the bulk of a class's non access and inquiry method methods here. A programmer will look here for the meat of a class's interface.

ACCESS

Place attribute accessors here.

INQUIRY

These are the Is* methods. Whenever you have a question to ask about an object it can be asked via in Is method. For example: IsOpen() will indicate if the object is open. A good strategy is instead of making a lot of access methods you can turn them around to be questions about the object thus reducing the exposure of internal structure. Without the IsOpen() method we might have had to do: if (State() == STATE_OPEN) which is much uglier.

What should go in public/protected/private?

Public Section

Only put an object's interface in the public section. DO NOT expose any private data items in the public section. At least encapsulate access via access methods. Ideally your method interface should make most access methods unnecessary.

Protected and Private Section

What should go into the protected section versus the private section is always a matter of debate.

All Protected

Some say there should be no private section and everything not in the public section should go in the protected section. Afterall, we should allow all our children to change anything they wish.

All Private

Another camp says by making the public interface virtual any derived class can change behaviour without mucking with internals.

Wishy Washy

Rationally decide where elements should go and put them there. Not very helpful.

And the Winner Is...

Keeping everything all private seems the easiest approach. By making the public methods virtual flexibility is preserved.

Method Layout

In a class header the method header is extracted as part of class's documentation. The header for an implementation method in a source file will use the same method header as described here, but with different content.

Method Header

A simple method can just have a one line comment to the right of a method as in:
   XX&                     operator=(XX);        // assignment operator

More indepth explanations require a method header. The header can go under or over the method signature. Traditionally headers go above the method, but under the method works nice too. The method header has the following format:

   int                     AnyMethod();
                           // Description
                           // RETURN: OK: success FAIL: a bad thing happened

or
                           // Description
                           // PRECONDITION:
                           //   The Open() method MUST be called before this.
                           // WARNING:
                           // LOCK REQUIRED: lock name
                           // SEE ALSO:
                           // RETURN: OK: success FAIL: a bad thing happened
                           //
   int                     AnyMethod();
                           

Description

Describe the method, what it's for, what it does, etc.. Try and include time and space tradeoffs where necessary.

RETURN

Document what values can be return and what their return means.

PRECONDITION

Document what must have happened for the object to be in a state where the method can be called.

WARNING

Document anything unusual users should know about this method.

LOCK REQUIRED

Some methods require a semaphore be aquired before using the method. When this is the case use lock required and specify the name of the lock.

SEE ALSO

Refer users to related methods, classes, or resources.

Formatting Methods with Multiple Arguments

We should try and make methods have as few parameters as possible. If you find yourself passing the same variables to every method then that variable should probably be part of the class. When a method does have a lot of parameters format it like this:
   int                     AnyMethod(
                              int   arg1,           // comment
                              int   arg2,           // comment
                              int   arg3,           // comment
                              int   arg4);          // comment
                           // Description
                           // RETURN: OK: success FAIL: a bad thing happened
Comment each attribute when necessary. Such documentation can be very useful for class users.

Include Statement Documentation

Include statements should be documented, telling the user why a particular file was included. If the file includes a class used by the class then it's useful to specify a class relationship:

Example

///X///////////////////////X////////////////////X/////////////////////////////

#ifndef _XX_h_
#define _XX_h_

// SYSTEM INCLUDES
//
#include "stdio.h"                             // standard IO interface
#include "String.h"                            // HASA string interface

Notice how the comments for include statements align on the third X.

Block Comments

Use comments on starting and ending a Block:
{  // Block1  (meaningful comment about Block1)
  ... some code
  {  // Block2  (meaningful comment about Block2)
    ... some code
  }  // End Block2
  ... some code
}  // End Block1
This may make block matching much easier to spot when you don't have an intelligent editor.


Do Not do Real Work in Object Constructors

Do not do any real work in an object's constructor. Inside a constructor initialize variables only and/or do only actions that can't fail.

Create an Open() method for an object which completes construction. Open() should be called after object instatiation.

Justification

Example

   class Device
   {
      Device();
      int Open();
   }

   Device dev;
   if (dev.Open()) exit(1);


Be Careful Throwing Exceptions in Destructors

An object is presumably created to do something. Some of the changes made by an object should persist after an object dies (is destructed) and some changes should not. Take an object implementing a SQL query. If a database field is updated via the SQL object then that change should persist after the SQL objects dies. To do its work the SQL object probably created a database connection and allocated a bunch of memory. When the SQL object dies we want to close the database connection and deallocate the memory, otherwise if a lot of SQL objects are created we will run out of database connections and/or memory.

The logic might look like:

Sql::~Sql()
{
   delete connection;
   delete buffer;
}

Let's say an exception is thrown while deleting the database connection. Will the buffer be deleted? No. Exceptions are basically non-local gotos with stack cleanup. The code for deleting the buffer will never be executed creating a gaping resource leak.

Special care must be taken to catch exceptions which may occur during object destruction. Special care must also be taken to fully destruct an object when it throws an exception.


Prototype Source File

// NAME: 
//   XX -
//
// SYNOPSIS:
// DESCRIPTION:
// EXAMPLES:
// FILES:
// BUGS:
// SEE ALSO:
// TYPE: C++-SOURCE
///X///////////////////////X////////////////////X/////////////////////////////

#include "XX.h"                                // class implemented


/////////////////////////////// PUBLIC ///////////////////////////////////////

//============================= LIFECYCLE ====================================

XX::XX()
{
}// XX

XX::XX(const XX&)
{
}// XX

XX::~XX()
{
}// ~XX


//============================= OPERATORS ====================================

XX& 
XX::operator=(XX&);
{
   return *this;

}// =

//============================= OPERATIONS ===================================
//============================= ACESS      ===================================
//============================= INQUIRY    ===================================
/////////////////////////////// PROTECTED  ///////////////////////////////////

/////////////////////////////// PRIVATE    ///////////////////////////////////


Make Functions Reentrant

Functions should not keep static variables that prevent a function from being reentrant.


To Use Enums or Not to Use Enums

C++ allows constant variables, which should depreciate the use of enums as constants. Unfortunately in most compilers constants take space. Some compilers will remove constants, but not all. Contants taking space precludes them from being used in tight memory environments like embedded systems. Workstation users should use constants and ignore the rest of this discussion.

In general enums are preferred to #define as enums are understood by the debugger.

Be aware enums are not of a guaranteed size. So if you have a type that can take a known range of values and it is transported in a message you can't use an enum as the type. Use the correct integer size and use constants or #define. Casting between integers and enums is very error prone as you could cast a value not in the enum.

A C++ Workaround

C++ allows static class variables. These variables are available anywhere and only the expected amount of space is taken.

Example

class Variables
{
public:
   static const int   A_VARIABLE;
   static const int   B_VARIABLE;
   static const int   C_VARIABLE;
}


Use Header File Guards

Include files should protect against multiple inclusion through the use of guards:
#ifndef _ClassName_h_
#define _ClassName_h_

#endif // _ClassName_h_
Replace ClassName with the name of the class contained in the file. Use the exact class name. Some standards say use all upper case. This is a mistake because someone could actually name a class the same as yours but using all upper letters. If the files end up be included together one file will prevent the other from being included and you will be one very confused puppy. It's happened!

When the include file is not for a class then the file name should be used as the guard name.


A Line Should Not Exceed 78 Characters

Justification


If Then Else Formatting

Layout

It's up to the programmer. Different bracing styles will yield slightly different looks. One common approach is:
   if (condition)                 // Comment
   {
   } 
   else if (condition)            // Comment
   {
   }
   else                           // Comment
   {
   }
If you have else if statements then it is usually a good idea to always have an else block for finding unhandled cases. Maybe put a log message in the else even if there is no corrective action taken.

Condition Format

Always put the constant on the left hand side of an equality/inequality comparison. For example:

if ( 6 == errorNum ) ...

One reason is that if you leave out one of the = signs, the compiler will find the error for you. A second reason is that it puts the value you are looking for right up front where you can find it instead of buried at the end of your expression. It takes a little time to get used to this format, but then it really gets useful.


switch Formatting

Example

   switch (...)
   {
      case 1:
         code
      // FALL THROUGH

      case 2:
      {        
         int v;
         code
      }
      break;

      default:
   }


Use of goto and ?:

Goto

Goto statements should be used sparingly, as in any well-structured code. The goto debates are boring so we won't go into them here. The main place where they can be usefully employed is to break out of several levels of switch, for, and while nesting, although the need to do such a thing may indicate that the inner constructs should be broken out into a separate function, with a success/failure return code.


   for (...) 
   {
      while (...) 
      {
         ...
         if (disaster)
            goto error;
      }
   }
   ...
error:
   clean up the mess 

When a goto is necessary the accompanying label should be alone on a line and to the left of the code that follows. The goto should be commented (possibly in the block header) as to its utility and purpose. Continue should be used sparingly and near the top of the loop. Break is less troublesome.

?:

The trouble is people usually try and stuff too much code in between the ? and :. Here are a couple of clarity rules to follow:

Example

   (condition) ? funct1() : func2();

   or

   (condition)
      ? long statement
      : another long statement;


Alignment of Declaration blocks

Justification

Example

   DWORD       mDword
   DWORD*      mpDword
   char*       mpChar
   char        mChar

   mDword   = 0;
   mpDword  = NULL;
   mpChar   = 0;
   mChar    = NULL;


Macros

Don't Turn C++ into Pascal

Don't change syntax via macro substitution. It makes the program unintelligible to all but the perpetrator.

Replace Macros with Inline Functions

In C++ macros are not needed for code efficiency. Use inlines.

Example

#define  MAX(x,y)	(((x) > (y) ? (x) : (y))	// Get the maximum

The macro above can be replaced for integers with the following inline function with no loss of efficiency:

   inline int 
   max(int x, int y)
   {
      return (x > y ? x : y);
   }

Be Careful of Side Effects

Macros should be used with caution because of the potential for error when invoked with an expression that has side effects.

Example

   MAX(f(x),z++);


Initialize all Variables

Justification


Init Idiom for Initializing Objects

Justification

Example

   class Test
   {
   public:
      Test()
      {
         Init();   // Call to common object initializer
      }

      Test(int val)
      {
         Init();   // Call to common object initializer
      }

   private:
      int      mVal;
      String*  mpName;

      void Init()
      {
         mVal  = 0;
         mpName= 0;
      }
   }


One Statement Per Line

There should be only one statement per line unless the statements are very closely related.


Short Methods

Justification


Document Null Statements

Always document a null body for a for or while statement so that it is clear that the null body is intentional and not missing code.

   while (*dest++ = *src++)
      ;         // VOID 


Do Not Default If Test to Non-Zero

Do not default the test for non-zero, i.e.

   if (f() != FAIL) 
is better than

   if (f()) 
even though FAIL may have the value 0 which C considers to be false. An explicit test will help you out later when somebody decides that a failure return should be -1 instead of 0. Explicit comparison should be used even if the comparison value will never change; e.g., if (!(bufsize % sizeof(int))) should be written instead as if ((bufsize % sizeof(int)) == 0) to reflect the numeric (not boolean) nature of the test. A frequent trouble spot is using strcmp to test for string equality, where the result should never ever be defaulted. The preferred approach is to define a macro STREQ.


   #define STREQ(a, b) (strcmp((a), (b)) == 0) 

The non-zero test is often defaulted for predicates and other functions or expressions which meet the following restrictions:


The Bull of Boolean Types

Any project using source code from many sources knows the pain of multiple conflicting boolean types. The new C++ standard defines a native boolean type. Until most compilers support boolean we must still deal with the cruel world.

The form of boolean most accurately matching the new standard is:


   typedef int     bool;
   #define FALSE   0
   #define TRUE    1
Even with these declarations, do not check a boolean value for equality with 1 (TRUE, YES, etc.); instead test for inequality with 0 (FALSE, NO, etc.). Most functions are guaranteed to return 0 if false, but only non-zero if true. Thus,

   if (func() == TRUE) { ... 
must be written

   if (func() != FALSE) { ... 


Usually Avoid Embedded Assignments

There is a time and a place for embedded assignment statements. In some constructs there is no better way to accomplish the results without making the code bulkier and less readable.


   while ((c = getchar()) != EOF) 
   {
      process the character
   }

The ++ and -- operators count as assignment statements. So, for many purposes, do functions with side effects. Using embedded assignment statements to improve run-time performance is also possible. However, one should consider the tradeoff between increased speed and decreased maintainability that results when embedded assignments are used in artificial places. For example,


   a = b + c;
   d = a + r; 
should not be replaced by

   d = (a = b + c) + r; 
even though the latter may save one cycle. In the long run the time difference between the two will decrease as the optimizer gains maturity, while the difference in ease of maintenance will increase as the human memory of what's going on in the latter piece of code begins to fade.


Reusing Your Hard Work and the Hard Work of Others

Reuse across projects is almost impossible without a common framework in place. Objects conform to the services available to them. Different projects have different service environments making object reuse difficult.

Developing a common framework takes a lot of up front design effort. When this effort is not made, for whatever reasons, there are several techniques one can use to encourage reuse:

Ask! Email a Broadcast Request to the Group

This simple technique is rarely done. For some reason programmers feel it makes them seem less capable if they ask others for help. This is silly! Do new interesting work. Don't reinvent the same stuff over and over again.

If you need a piece of code email to the group asking if someone has already done it. The results can be suprising.

In most large groups individuals have no idea what other people are doing. You may even find someone is looking for something to do and will volunteer to do the code for you. There's always a gold mine out there if people work together.

Tell! When You do Something Tell Everyone

Let other people know if you have done something reusable. Don't be shy. And don't hide your work to protect your pride. Once people get in the habit of sharing work everyone gets better.

Don't be Afraid of Small Libraries

One common enemy of reuse is people not making libraries out of their code. A reusable class may be hiding in a program directory and will never have the thrill of being shared because the programmer won't factor the class or classes into a library.

One reason for this is because people don't like making small libraries. There's something about small libraries that doesn't feel right. Get over it. The computer doesn't care how many libraries you have.

If you have code that can be reused and can't be placed in an existing library then make a new library. Libraries don't stay small for long if people are really thinking about reuse.

If you are afraid of having to update makefiles when libraries are recomposed or added then don't include libraries in your makefiles, include the idea of services. Base level makefiles define services that are each composed of a set of libraries. Higher level makefiles specify the services they want. When the libraries for a service change only the lower level makefiles will have to change.

Keep a Repository

Most companies have no idea what code they have. And most programmers still don't communicate what they have done or ask for what currently exists. The solution is to keep a repository of what's available.

In an ideal world a programmer could go to a web page, browse or search a list of packaged libraries, taking what they need. If you can set up such a system where programmers voluntarily maintain such a system, great. If you have a librarian in charge of detecting reusability, even better.

Another approach is to automatically generate a repository from the source code. This is done by using common class, method, library, and subsystem headers that can double as man pages and repository entries.


Comments on Comments

Comments Should Tell a Story

Consider your comments a story describing the system. Expect your comments to be extracted by a robot and formed into a man page. Class comments are one part of the story, method signature comments are another part of the story, method arguments another part, and method implementation yet another part. All these parts should weave together and inform someone else at another point of time just exactly what you did and why.

Document Decisions

Comments should document decisions. At every point where you had a choice of what to do place a comment describing which choice you made and why. Archeologists will find this the most useful information.

Use Headers

Other sections in this document describe various header comment blocks for specifying a class, method signature, method argument, a method in source file, and the fine grain parts of a method's implementation.

These headers are structured in such a way as they can be parsed and extracted. They are not useless like normal headers. So take time to fill them out. If you do it right once no more documentation may be necessary.

Comment Layout

Each part of the project has a specific comment layout.

Make Gotchas Explicit

Explicitly comment variables changed out of the normal control flow or other code likely to break during maintenance. Embedded keywords are used to point out issues and potential problems. Consider a robot will parse your comments looking for keywords, stripping them out, and making a report so people can make a special effort where needed.

Gotcha Keywords

Gotcha Formatting

Example

   // :TODO: tmh 960810: possibile performance problem
   // We should really use a hash table here but for now we'll
   // use a linear search.

   // :KLUDGE: tmh 960810: possible unsafe type cast
   // We need a cast here to recover the derived type. It should
   // probably use a virtual method or template.

See Also

See Interface and Implementation Documentation for more details on how documentation should be laid out.


Interface and Implementation Documentation

There are two main audiences for documentation: With a little forthought we can extract both types of documentation directly from source code.

Class Users

Class users need class interface information which when structured correctly can be extracted directly from a header file. When filling out the header comment blocks for a class, only include information needed by programmers who use the class. Don't delve into algorithm implementation details unless the details are needed by a user of the class. Consider comments in a header file a man page in waiting.

Class Implementors

Class implementors require indepth knowledge of how a class is implemented. These type of comments will be found in the source file(s) implementing a class. Don't worry about interface issues. Header comment blocks in a source file should cover alogorithm issues and other design decisions. Comment blocks within a method's implementation should explain even more.


Directory Documentation

Every directory should have a README file that covers: Consider a new person coming in 6 months after every original person on a project has gone. That lone scared explorer should be able to piece together a picture of the whole project by traversing a source directory tree and reading README files, Makefiles, and source file headers.


Follow the Law of Demeter

The Law of Demeter states that you shouldn't access a contained object directly from the containing object, you should use a method of the containing object that does what you want and accesses any of its objects as needed.

Justification

The purpose of this law is to break dependencies so implementations can change without breaking code. If an object wishes to remove one of its contained objects it won't be able to do because some other object is using it. If instead the service was through an interface the object could change its implementation anytime without ill effect.

Caveat

As for most laws the Law of Demeter should be ignored in certain cases. If you have a really high level object that contains a lot of subobjects, like a car contains thousands of parts, it can get absurd to created a method in car for every access to a subobject.

Example

   class SunWorkstation
   {
      void          UpVolume(int amount) { mSound.Up(amount); }

      SoundCard     mSound;

   private:
      GraphicsCard  mGraphics;
   }

   SunWorksation sun;

   Do   : sun.UpVolume(1);
   Don't: sun.mSound.Up(1);


Minimize Dependencies with Abstract Base Classes

One of the most important strategies in C++ is to remove dependencies among different subsytems. Abstract base classes (ABCs) are a solid technique for dependency removal.

An ABC is an abstraction of a common form such that it can be used to build more specific forms. An ABC is a common interface that is reusable across a broad range of similar classes. By specifying a common interface as long as a class conforming to that interface is used it doesn't really matter what is the type of the derived type. This breaks code dependencies. New classes, conforming to the interface, can be substituted in at will without breaking code. In C++ interfaces are specified use base classes with virtual methods.

The above is a bit rambling because it's a hard idea to convey. So let's use an example: We are doing a GUI where things jump around on the screen. One approach is to do something like:

   class Frog
   {
   public:
      void Jump();
   }
   class Bean
   {
   public:
      void Jump();
   }
The GUI folks could instantiate each object and call the Jump method of each object. The Jump method of each object contains the implementation of jumping behaviour for that type of object. Obviously frogs and beans jump differently even though both can jump.

Unfortunately the owner of Bean didn't like the word Jump so they changed the method name to Leap. This broke the code in the GUI and one whole week was lost.

Then someone wanted to see a horse jump so a Horse class was added:

   class Horse
   {
   public:
      void Jump();
   }
The GUI people had to change their code again to add Horse.

Then some updated Horse so that its Jump behaviour was slightly different. Unfortunately this caused a total recompile of the GUI code and they were pissed.

Someone got the bright idea of trying to remove all the above dependencies using abstract base classes. They made one base class that specified an interface for jumping things:

   class Jumpable
   {
   public:
      virtual void Jump() = 0;
   }
Jumpable is a base class because other classes need to derive from it so they can get Jumpable's interface. It's an abstract base class because one or more of its methods has the = 0 notation which means the method is a pure virtual method. Pure virtual methods must be implemented by derived classes. The compiler checks.

Not all methods in an ABC must be pure virtual, some may have implementation. This is especially true when creating a base class encapsulating a process common to a lot of objects. For example, devices that must be opened, diagnostics run, booted, executed, and the closed on a certain event may create an ABC called Device that has a method called LifeCycle which calls all other methods in turn thus running through all phases of a device's life. Each device phase would have a pure virtual method in the base class requiring implementation by more specific devices. This way the process of using a device is made common but the specifics of a device are hidden behind a common interface.

Back to Jumpable. All the classes were changed to derive from Jumpable:

   class Frog : public Jumpable
   {
   public:
      virtual void Jump() { jump frog jump; }
   }

   etc ...
We see an immediate benifit: we know all classes derived from Jumpable must have a Jump method. No one can go changing the name to Leap without the compiler complaining. One dependency broken.

Another benifit is that we can pass Jumpable objects to the GUI, not specific objects like Horse or Frog:

   class Gui
   {
   public:
      void MakeJump(Jumpable*);
   }

   Gui gui;
   Frog* pFrog= new Frog;
  
   gui.MakeJump(pFrog); 
Notice Gui doesn't even know it's making a frog jump, it just has a jumpable thing, that's all it cares about. When Gui calls the Jump method it will get the implementation for Frog's Jump method. Another dependency down. Gui doesn't have to know what kind of objects are jumping.

We also removed the recompile dependency. Because Gui doesn't contain any Frog objects it will not be recompiled when Frog changes.

Downside

Wow! Great stuff! Yes but there are a few downsides:

Overhead for Virtual Methods

Virtual methods have a space and time penalty. It's not huge, but should be considered in design.

Make Everything an ABC!

Sometimes people overdo it, making everything an ABC. The rule is make an ABC when you need one not when you might need one. It's takes effort to design a good ABC, throwing in a virtual method doesn't an ABC make. Pick and choose your spots. When some process or some interface can be reused and people will actually make use of the reuse then make an ABC and don't look back.


Use a Design Notation and Process

Programmers need to have a common language for talking about coding, designs, and the software process in general. This is critical to project success.

Any project brings together people of widely varying skills, knowledge, and experience. Even if everyone on a project is a genius you will still fail because people will endlessly talk past each other because there is no common language and processes binding the project together. All you'll get is massive fights, burnout, and little progress. If you send your group to training they may not come back seasoned experts but at least your group will all be on the same page; a team.

There are many popular methodologies out there. Many companies use the Booch methodology which will soon be replaced by the Unified Methodology. The point is to do some research, pick a method, train your people on it, and use it. Take a look at the top of this page for links to various methodologies.

You may find the CRC (class responsibility cards) approach to teasing out a design useful. Many others have. It is an informal approach encouraging team cooperation and focusing on objects doing things rather than objects having attributes. There's even a whole book on it: Using CRC Cards by Nancy M. Wilkinson.


Using Use Cases

A use case is a generic description of an entire transaction involving several objects. A use case can also describe the behaviour of a set of objects, such as an organization. A use case model thus presents a collection of use cases and is typically used to specify the behaviour of a whole application system together with one or more external actors that interact with the system.

An individual use case may have a name (although it is typically not a simple name). Its meaning is often written as informal text description of the external actors and the sequences of events between objects that make up the transaction. Use cases can include other use cases as part of their behaviour.

Requirements Capture

Use cases attempt to capture the requirements for a system in an understandable form. The idea is by running through a set of use case we can verify that the system is doing what it should be doing.

Have as many use cases as needed to describe what a system needs to accomplish.

The Process


Unified Modeling Language

The Unified Modeling Language is too large to present here. Fortunately you can see it at Rational's web site. Since you do need a modeling language UML is a safe choice. It combines features from several methods into one unified language. Remember all languages and methods are open to local customozation. If their langauge is too complex then use the parts you and your project feel they need and junk the rest.


OPEN Method

OPEN stands for Object-oriented Process, Environment and Notation and is a worthy if not superior competitor to UML. It is another group effort composed of basically all the people not in the UML group :-) Their web site has a good comparison of OPEN and UML.

My guess is UML will win out for marketing reasons. But it is good to have some competition going.


Liskov's Substitution Principle (LSP)

This principle states:
   All classes derived from a base class should be interchangeable
   when used as a base class.
The idea is users of a class should be able to count on similar behaviour from all classes that derive from a base class. No special code should be necessary to qualify an object before using it. If you think about it violating LSP is also violating the Open/Closed . principle because the code would have to be modified everytime a derived class was added.

For example, if the Jump method of a Frog object implementing the Jumpable interface actually makes a call and orders pizza we can say its implementation is not in the spirit of Jump and probably all other objects implementing Jump. Before calling a Jump method a programmer would now have to check for the Frog type so it wouldn't screw up the system. We don't want this in programs. We want to use base classes and feel comfortable we will get consistent behaviour.

LSP is a very restrictive idea. It constrains implementors quite a bit. In general people support LSP and have LSP as a goal.


Open/Closed Principle

The Open/Closed principle states a class must be open and closed where: The Open/Closed principle is a pitch for stability. A system is exetended by adding new code not by changing already working code. Programmers often don't feel comfortable changind old code because it works! This principle just gives you an academic sounding justification for your fears :-)

In practice the Open/Closed principle simple means making good use of our old friends abstraction and polymorphism. Abstraction to factor out common processes and ideas. Inheritence to create an interface that must be adhered to by derived classes. In C++ we are talking about using abstract base classes . A lot.


Design by Contract

The idea of design by contract is strongly related to LSP . A contract is a formal statement of what to expect from another party. In this case the contract is between pieces of code. An object and/or method states that it does X and you are supposed to believe it. For example, when you ask an object for it's volume that's what you should get. And because volume is a verifiable attribute of a thing you could run a series of checks to verify volume is correct, that is, it satisfies its contract.

The contract is enforced in languages like Eiffle by pre and post condition statements that are actually part of the language. In other langauges a bit of faith is needed.

Design by contract when coupled with language based verification mechanisms is a very powerful idea. It makes programming more like assembling spec'd parts.


Don't Over Use Operators

C++ allows the overloading of all kinds of weird operators. Unless you are building a class directly related to math there are very few operators you should override. Only override an operator when the semantics will be clear to users.

Justification


Class File Layout

Class Definition in One File

Each class definition should be in its own file where each file is named directly after the class's name:
   ClassName.h

Implementation in One File

In general each class should be imlemented in one source file:
   ClassName.C   // or whatever the extension is: cpp, c++

But When it Gets Really Big...

If the source file gets too large or you want to avoid compiling templates all the time then add additional files named according to the following rule:
   ClassName_section.C
section is some name that identifies why the code is chunked together. The class name and section name are separated by '_'.


Miscellaneous

This section contains some miscellaneous do's and dont's.


Be Const Correct

C++ provides the const key word to allow passing as parameters objects that cannot change to indicate when a method doesn't modify its object. Using const in all the right places is called "const correctness." It's hard a first but using const really tightens up your coding style. Usually people start by not be const correct and the moving to be so.

For more information see Const Correctness in the C++ FAQ.


Use Streams

Programmers transitioning from C to C++ find stream IO strange prefering the familiarity of good old stdio. Printf and gang are very convenient, efficient, functional, and well understood.

Type Safety

Stdio is not type safe, which is one of the reasons you are using C++, right? Stream IO is type safe. That's one good reason to use streams.

Standard Interface

When you want to dump an object to a stream there is a standard way of doing it: with the << operator. This is not true of objects and stdio.

Interchangeablity of Streams

One of the more advanced reasons for using streams is that once an object can dump itself to a stream it can dump itsself to any stream. One stream may go to the screen, but another stream may be a serial port or network connection. Good stuff.

Streams Got Better

Stream IO is not perfect. It is however a lot better than it used to be. Streams are now standardized, acceptably efficient, more reliable, and now there's lots of documentation on how to use streams.

But Not Perfect

For an embedded target tight on memory streams do not make sense. Streams inline a lot of code so you might find the image larger than you wish. Experiment a little. Streams might work on your target.


Register/Dispatch Idiom

Another strategy for reducing dependencies in a system is the Register/Dispatch Idiom (RDI). RDI treats large grained occurances in a system as events. Events are identified by some unique identifier. Objects in the system register with a dispatch system for events or classes of events it is interested in. Objects that are event sources send events into the dispatch system so the dispatch system can route events to consumers.

RDI separates producers and consumers on a distributed scale. Event producers and consumers don't have to know about each other at all. Consumers can drop out of the event stream by deregistering for events. New consumers can register for events at anytime. Event producers can drop out with no ill effect to event consumers, the consumer just won't get any more events. Allthough it is a good idea for producers to have an "i'm going down event" so consumers can react intelligently.

Logically the dispatch system is a central entity. The implementation however can be quite different. For a highly distributed system a truly centralized event dispatcher would be a performance bottleneck and a single point of failure. Think of event dispatchers as being a lot of different processes cast about on various machines for redundancy purposes. Event processors communicate amongst each other to distribute knowledge about event consumers and producers. Much like a routing protocol distributes routing information to its peers.

RDI works equally well in the small, in processes and single workstations. Parts of the system can register as event consumers and event producers making for a very flexible system. Complex decisions in a system are expressed as event registrations and deregistrations. No further level of cooperation required.

More expressive event filters can also be used. The above proposal filters events on some unique ID. Often you want events filtered on more complex criteria, much like a database query. For this to work the system has to understand all data formats. This is easy if you use a common format like attribute value pairs. Otherwise each filter needs code understanding packet formats. Compiling in filter code to each dispatcher is one approach. Creating a downloadable generic stack based filter language has been used with success on other projects, being both simple and efficient.


Envelope Letter Idiom

TBD


Different Accessor Styles

Why Accessors?

Access methods provide access to the physical or logical attributes of an object. Accessing an object's attributes directly as we do for C structures is greatly discouraged in C++. We Disallow direct access to attributes to break dependencies, the reason we do most things. Directly accessing an attribute exposes implementation details about the object.

To see why ask yourself:

If any of the above changed code would break. An object makes a contract with the user to provide access to a particular attribute, it should not promiss how it gets those attributes. Accessing a physical attribute makes such a promiss.

Accessors Considered Somewhat Harmful

At least in the public interface having accessors many times is an admission of failure, a failure to make an object's inteface complete. At the protected or private level accessors are fine as these are the implementation levels of a class.

Implementing Accessors

There are three major idioms for creating accessors.

Get/Set

   class X
   {
   public:
      int    GetAge() const     { return mAge; }
      void   SetAge(int age)    { mAge= age; }
   private:
      int mAge;
   }
The problem with Get/Set is twofold: One benefit, that it shares with the One Method Name, is when used with messages the set method can transparently transform from native machine representations to network byte order.

One Method Name

   class X
   {
   public:
      int    Age() const     { return mAge; }
      void   Age(int age)    { mAge= age; }
   private:
      int mAge;
   }
Similar to Get/Set but cleaner. Use this approach when not using the Attributes as Objects approach.

Attributes as Objects

   class X
   {
   public:
      int              Age() const     { return mAge; }
      int&             rAge()          { return mAge; } 

      const String&    Name() const    { return mName; }
      String&          rName()         { return mName; }
   private:
      int              mAge;
      String           mName;
   }
The above two attribute examples shows the strength and weakness of the Attributes as Objects approach.

When using an int type, which is not a real object, the int is set directly because rAge() returns a reference. The object can do no checking of the value or do any representation reformating. For many attributes however these are not horrible restrictions.

An object implementing the = operator overcomes all the above reservations and is more inline with the object philosophy: the object should do it. An object's = operator can do all the checks for the assignment and it's done once in one place, in the object, where it belongs. It's also clean from a name perspective.

When possible use this approach to attribute access.


Layering

Layering is the primary technique for reducing complexity in a system. A system should be divided into layers. Layers should communicate between adjacent layers using well defined interfaces. When a layer uses a non-adjacent layer then a layering violation has occurred.

A layering violation simply means we have dependency between layers that is not controlled by a well defined interface. When one of the layers changes code could break. We don't want code to break so we want layers to work only with other adjacent layers.

Sometimes we need to jump layers for performance reasons. This is fine, but we should know we are doing it and document appropriately.


Delegation

Delegation is the idea of a method using another object's method to do the real work. In some sense the top layer method is a front for the other method. Delegation is a form of dependency breaking. The top layer method never has to change while it's implementaion can change at will.

Delegation is an alternative to using inheritence for implementation purposes. One can use inheritance to define an interface and delegation to implement the interface.

Some people feel delegation is a more robust form of OO than using implementation inheritance. Delegation encourages the formation of abstract class interfaces and HASA relationships. Both of which encourage reuse and dependency breaking.

Example

   class TestTaker
   {
   public:
      void WriteDownAnswer()   { mPaidTestTaker.WriteDownAnswer(); } 
   private:
      PaidTestTaker  mPaidTestTaker;
   }
In this example a test taker delegates actually answering the question to a paid test taker. Not ethical but a definite example of delegation!


Code Reviews

If you can make a formal code review work then my hat is off to you. Code reviews can be very useful. Unfortunately they often degrade into nit picking sessions and endless arguments about silly things. They also tend to take a lot of peoples time for a questionable payback.

My god he's questioning code reviews, he's not an engineer!

Not really, it's the form of code reviews and how they fit into normally late chaotic projects is what is being questioned.

First, code reviews are way too late to do much of anything useful. What needs reviewing are requirements and design. This is where you will get more bang for the buck.

Get all relevant people in a room. Lock them in. Go over the class design and requirements until the former is good and the later is being met. Having all the relevant people in the room makes this process a deep frutiful one as questions can be immediately answered and issues immediately explored. Usually only a couple of such meetings are necessary.

If the above process is done well coding will take care of itself. If you find problems in the code review the best you can usually do is a rewrite after someone has sunk a ton of time and effort into making the code "work."

You will still want to do a code review, just do it offline. Have a couple people you trust read the code in question and simply make comments to the programmer. Then the programmer and reviewers can discuss issues and work them out. Email and quick pointed discussions work well. This approach meets the goals and doesn't take the time of 6 people to do it.


Create a Source Code Control System Early and Not Often

A common build system and source code control system should be put in place as early as possible in a projects lifecycle, preferably before anyone starts coding. Source code control is the structural glue binding a project together. If programmers can't easily use each others products then you'll never be able to make a good reproducable build and people will piss away a lot of time. It's also hell converting rogue build environments to a standard system. But it seems the right of passage for every project to build their own custom environment that never quite works right.

Some issues to keep in mind:

Sources

If you have the money many projects have found
Clear Case a good system. Perfectly workable systems have been build on top of GNU make and CVS. CVS is a freeware build environment built on top of RCS. It's main difference from RCS is that is supports a shared file model to building software.


Create a Bug Tracking System Early and Not Often

The earlier people get used to using a bug tracking system the better. If you are 3/4 through a project and then install a bug tracking system it won't be used. You need to install a bug tracking system early so people will use it.

Allthough programmers generally resist bug tracking when used correctly it can really help a project:

Not sexy things, just good solid project improvements.

FYI, it's not a good idea to reward people by the number of bugs they fix :-)

Source code control should be linked to the bug tracking system. During the part of a project where source is freezed before a release only checkins accompanied by a valid bug ID should be accepted. And when code is changed to fix a bug the bug ID should be included in the checkin comments.

Sources

Several projects have found
DDTS a workable system. There is also a GNU bug tracking system available allthough I have never used it. Roll your own is a popular option but using an existing system seems more cost efficient.


Honor Responsibilities

Responsibility for software modules is scoped. Modules are either the responsibility of a particular person or are common. Honor this division of responsibility. Don't go changing things that aren't your responsibility to change. Only mistakes and hard feelings will result.

Face it, if you don't own a piece of code you can't possibly be in a position to change it. There's too much context. Assumptions seemingly reasonable to you may be totally wrong. If you need a change simply ask the responsible person to change it. Or ask them if it is OK to make such-n-such a change. If they say OK then go ahead, otherwise holster your editor.

Every rule has exceptions. If it's 3 in the morning and you need to make a change to make a dileverable then you have to do it. If someone is on vacation and no one has been assigned their module then you have to do it. If you make changes in other peoples code try and use the same style they have adopted.

Programmers need to mark with comments code that is particularly sensitive to change. If code in one area requires changes to code in an another area then say so. If changing data formats will cause conflicts with persistent stores or remote message sending then say so. If you are trying to minimize memory usage or achieve some other end then say so. Not everyone is as brilliant as you.

The worst sin is to flit through the system changing bits of code to match your coding style. If someone isn't coding to the standards then ask them or ask your manager to ask them to code to the standards. Use common courtesy.

Code with common responsibility should be treated with care. Resist making radical changes as the conflicts will be hard to resolve. Put comments in the file on how the file should be extended so everyone will follow the same rules. Try and use a common structure in all common files so people don't have to guess on where to find things and how to make changes. Checkin changes as soon as possible so conflicts don't build up.

As an aside, module responsibilities must also be assigned for bug tracking purposes.


C++ File Extensions

In short: Use the .h extension for header files and .cc for source files.

For some reason an odd split occurred in early C++ compilers around what C++ source files should be called. C header files always use the .h and and C source files always use the .c extension. What should we use for C++?

The short answer is as long as everyone on your project agrees it doesn't really matter. The build environment should be able to invoke the right compiler for any extension. Historically speaking here have been the options:

Header File Extension Discussion

Using .hh extension is not widely popular but makes a certain kind of sense. C header files use .h file extension and C++ based header files use .hh file extension. The problem is if we consider a header file an
interface to a service then we can have a C interface to a service and C++ interface to the service in the same file. Using preprocessor directives this is possible and common. The recommendation is to stick with using the .h extension.

Source File Extension Discussion

The problem with the .C extension is that it is indistinguishable from the .c extensions in operating systems that aren't case sensitive. Yes, this is a UNIX vs. windows issue. Since it is a simple step aiding portability we won't use the .C extension. The .cpp extension is a little wordy. So the .cc extension wins by default.


Mixing C and C++

In order to be backward compatible with dumb linkers C++'s link time type safety is implemented by encoding type in formation in link symbols, a process called name mangling. This creates a problem when linking to C code as C function names are not mangled. When calling a C function from C++ the function name will be mangled unless you turn it off. Name mangling is turned off with the extern "C" syntax. If you want to create a C function in C++ you must wrap it with the above syntax. If you want to call a C function in a C library from C++ you must wrap in the above syntax. Here are some examples:

Calling C Functions from C++

extern "C" int strncpy(...);
extern "C" int my_great_function();
extern "C"
{
   int strncpy(...);
   int my_great_function();
};

Creating a C Function in C++

extern "C" void
a_c_function_in_c++(int a)
{
}

__cplusplus Preprocessor Directive

If you have code that must compile in a C and C++ environment then you must use the __cplusplus preprocessor directive. For example:

#ifdef __cplusplus

extern "C" some_function();

#else

extern some_function();

#endif


No Magic Numbers

A magic number is a bare naked number used in source code. It's magic because no-one has a clue what it means including the author inside 3 months. For example:

if      (22 == foo) { start_thermo_nuclear_war(); }
else if (19 == foo) { refund_lotso_money(); }
else if (16 == foo) { infinite_loop(); }
else                { cry_cause_im_lost(); }
In the above example what do 22 and 19 mean? If there was a number change or the numbers were just plain wrong how would you know? Instead of magic numbers use a real name that means something. You can use #define or constants or enums as names. Which one is a design choice. For example:
#define   PRESIDENT_WENT_CRAZY  (22)
const int WE_GOOFED= 19;
enum 
{
   THEY_DIDNT_PAY= 16
};

if      (PRESIDENT_WENT_CRAZY == foo) { start_thermo_nuclear_war(); }
else if (WE_GOOFED            == foo) { refund_lotso_money(); }
else if (THEY_DIDNT_PAY       == foo) { infinite_loop(); }
else                                  { happy_days_i_know_why_im_here(); }
Now isn't that better?


Promiss of OO

OO has been hyped to the extent you'd figure it would solve world hunger and usher in a new era of world peace. Not! OO is an approach, a philosphy, it's not a recipe which blindly followed yields quality.

Robert Martin put OO in perspective:


You can't use OO and C++ on Embedded Systems

Oh yes you can. I've used C++ on several embedded systems as have many others. And if you can't why not? Please don't give in to vague feelings and prejudice. An attitude best shown with a short exchange:
Rube: Our packet driver is slow. We're only getting 100 packets per second.
Me  : Good thing you didn't do it in C++ huh?
Rube: Oh yah, it would have been really slow then!
Me  : (smiled secretly to myself)
My initial response was prompted by a general unacceptance of C++ in the project and blaming C++ for all problems. Of course all the parts written in C and assembly had no problems :-). Embedded systems shops tend to be hardware driven companies and tend not do know much about software development, thus any new fangled concepts like OO and C++ are rediculed without and verbally accessible reasons. Counter arguments like code that is fast and small and resuable don't make a dent. Examples like improving the speed of a driver by inlining certain methods and not hacking the code to death gently roll into the bit bucket.

Techniques

Of course C++ can be a disaster for an embedded system when used incorrectly, which of course is true of any tool. Here's some ideas to use C++ safely in an embedded system:


Thin vs. Fat Class Interfaces

How many methods should an object have? The right answer of course is just the right amount, we'll call this the Goldilocks level. But what is the Goldilocks level? It doesn't exist. You need to make the right judgement for your situation, which is really what programmers are for :-)

The two extremes are thin classes versus thick classes. Thin classes are minimalist classes. Thin classes have as few methods as possible. The expectation is users will derive their own class from the thin class adding any needed methods.

While thin classes may seem "clean" they really aren't. You can't do much with a thin class. Its main purpose is setting up a type. Since thin classes hav