4.4 Organizing the Code

The code that defines, implements and uses classes is organized as a collection of files. For very small programs it is possible to put all of the code in a single file. Clearly, though, this is a poor practice for anything but the most trivial systems. The organization that is described below works for all cases and is the pattern universally used in practice.

Separating the Interface Definition and the Implementation

The definitions of classes are placed in header files while code files contain the code that implements or uses the classes. By convention, the header files are named with a ".h" suffix. The conventional suffix for code files varies with the compiler or system; typical code file suffixes are" ".C", ".cc", or ".cpp". The base part of a file's name is, of course, chosen to reflect the nature of its contents. Which code file suffix is used is not important - what is important is using the same suffix consistently.

Each header file contains one class definition or several highly related class definitions. For example, the header file named "Frame.h" contains only the Frame class. In a windowing system there might also be separate header files giving the class definitions for buttons, sliders, pens, and other elements typically found in graphical user-interface systems. In many cases there are groups of class definitions that are closely related and are grouped together in one header file. Such grouping occurs in one of two cases. First, the definition of a window class may involve the use of other classes, in which case these other classes may also be defined in the same header file. Second, the designer of a set of classes may believe that most often a user will want an entire set of class definitions; putting them in one header file makes it easier for the user since the user need only examine one header file to find all of the related classes. For example, a graphics system might provide classes for rectangles, circles, colors, and rulers. A single header file, perhaps named "Graphics.h", could be used to hold all of these definitions. In organizing the header files, it is important to be sure that only highly related class definitions are put in the same file.

The code implementing a class is placed in its own code file; for example, the code implementing the Frame class might be placed in the file "Frame.cc". Even if several classes are defined in the same header file, their implementations are typically placed in separate code files.

Definition before Use

Because C++ is a statically typed language, the C++ compiler must see the definition of a class before any uses are made of that class. Three important cases in which this rule must be satisfied are:

  • Compiling the implementation of a class: In translating each of the methods in a code file, the compiler must check that the signature of the method being compiled matches that of the signature of the method given in the header file. The compiler will detect errors if the method names do not match or if the number and/or types of arguments of a method do not match. In this case the compiler must see the header file of the class before it can successfully compile the code for that class's implementation.

  • Compiling the code of one class whose interface refers to another class: In several earlier examples it was seen that an object of one class (the argument class) is passed as a parameter in a method being invoked on a different class (the called class). In this case, the C++ compiler, when asked to compile the called class, must check that the argument class actually exists. In this case the compiler must see the definition of the argument class before it sees the definition of the interface of the called class.

  • Compiling the code of one class whose implementation refers to another class: It is common that methods in one class (the sender) invoke the methods of another class (the receiver). In this case the C++ compiler must check that the signature of the method invocation in the sender matches a method defined in the class of the receiver object. The compiler will detect an error and issue an error message if a match cannot be found. In this case the compiler must see the header file of the receiver class before it is able to compile the implementation of the sender class.

Examples of these three cases are shown below.

The Preprocessor

To insure that the source code is presented to the compiler in a define-before-use order, the source code is first scanned by a simple preprocessesor. The preprocessor (often named "cpp" for the C/C++ Preprocessor Program) looks for simple commands or directives in the files that it is scanning. A directive begins with a pound sign (#) in the first column and the rest of the line contains information about the directive. These directives are, stricly speaking, not part of the C++ language, and are understood only by the preprocessor. The preprocessor may scan many files, but it alway produces exactly one output file. Each line of input that is not a directive is either copied unchanged to the output file or simply ignored and not copied to the output file. The preprocessor may also modify lines before they are output, but how or why this is done is not of concern here.

One of the most basic directives of the preprocessor allows new files to be included in the set of files being scanned. This directive has the syntax #include filename. When multiple files are included, the preprocessor scans the files with the aid of a stack data structure. For example suppose that the preprocessor is told to scan file A and that:

  • File A contains some text, A1, then includes files B and C, then contains some text, A2
  • File B contains some text, B1, then includes file D, then contains some text, B2
  • File C contains some text, C1, then includes file D
  • File D includes file E and then contains some text D1
  • File E contains only text E1

In this case, the preprocessor would produce as its single output file the text in this order:

      A1, B1, E1, D1, B2, C1, E1, D1, A2

Notice that the processing order is stack-like. After scanning the text A1, the scanning of file A is suspended ("pushed on the stack"), while the scanning of the included files B and C is undertaken. Only after finishing the scanning of these included files is the scanning of file A resumed ("popped from the stack"). Also notice that files D and E appear twice in the output stream because file D was included twice, once from file B and once from file C.

Including Header Files

The preprocessor #include directive is used to insure that the compiler is presented with the source text in a define-before-use order. The example that follows shows how this directive should be used in header files and in the code files.

The Location class illustrates the first case in which a header file must be included. The interface and implementation of the Location class are shown again in the table below. Notice that the code file begins with an include directive.

Use of #include Directive in the Location Class
(in file Location.h)
(in file Location.cpp)
class Location { 
     int currentX, currentY;
    Location(int x, int y); 
    int Xcoord();  
    int Ycoord();  
#include "Location.h"

Location::Location( int x, int y ) 
   { currentX = x; currentY = y; }
Location::Location () 
   { currentX = -1; currentY = -1; }
int Location::Xcoord() 
   { return currentX; }
int Location::Ycoord() 
   { return currentY; }

The Message class is an example of the second case where include directives are needed. As shown below, the Message class interface refers to the Location and Frame classes because a Location object and Frame pointer appear as part of the private data of the class, and because the Message class methods take a Location object or a Frame reference as a parameter as well.

Use of #include Directive in the MessageClass
(in file Message.h)
(in file Message.cpp)
#include "Frame.h"
#include "Location.h"

class Message {
      char*    messageText;
      Frame*   frame;
      Location location;

      Message (char *textString, 
               Location whereAt);
      Message (Location whereAt);
void  DisplayIn (Frame& aFrame);
void  MoveTo (Location newLocation);
void  setText(char* newText);
char* getText();
void  Clear();
void  Draw ();
     ~Message ();
#include "Message.h"

Message::Message(char *textString,...) 
   { ... }
Message::Message(Location whereAt) 
   { ... }
void Message::DisplayIn(Frame& aFrame) 
   { ... }
void Message::MoveTo(Location newLocation) 
   { ... }
// rest of the Message class implementation

Notice that the code file (Message.cpp) includes the header file (Message.h) and that the header file of the Message class includes the header files of both the Location and Frame classes. It is not necessary for the code file to include the Location and Frame class header files because those have already been included by the Message class header file.

An example of the third case of using the include directive involves the FileChooser class that is shown in the table below. Notice that the interface of the FileChooser class uses only the single built-in type "char*" so there is no need to include any other files. The interface of the FileChooser does not depend on the interface of any other class. However, the implementation of the FileChooser does use two other classes, the Directory class and the Selector class. Objects of these two classes are used in the FileChooser's AskUser method. When compiling the code for the FileChooser class the compiler will need to verify that the Directory class defines methods named First() and Next() and that the Selector class defines methods named Add and AskUser. To satisfy the compiler's requirement, the implementation file, Choose.cpp, includes both Directry.h and Selector.h. It is important to note that the header file does not need to include either of these two files because the interface does not depend on the Directory and Selector classes, only the implementation depends on these two classes.

Use of #include Directive in the FileChooser Class
(in file Choose.h)
(in file Choose.cpp)
class FileChooser {

  char* thePath;
  char* theFilter;


 FileChooser(char* path, char* filter);
 FileChooser(char* path);       
 File AskUser();                      
#include "Choose.h "
#include " Directry.h "
#include " Selector.h "

// other code not shown
File FileChooser::AskUser() 
{ Directory directory(thePath, 
  Selector selector(thePath);
  char* nextName;
  char* fileChosen;

  nextName = directory.First();
  while (nextName) {
    nextName = directory.Next();
  fileChosen = selector.AskUser();
  return File(fileChosen);


Avoiding Duplicate Definitions

Care must be taken to avoid presenting the compiler with multiple definitions of the same class, even if these definitions are exactly the same. If the compiler sees two (even identical) definitions of the same class, it will issue an error message referring in some way to "multiple definitions" for the class. This situation can occur easily in practice when the preprocessor includes a header file twice in its output file. An example that follows will illustrate how easily it can happen. Additional preprocessor directives prevent this situation.

The BlinkingText program will be used to illustrate the problem of presenting the compiler with multiple definitions. The significant pieces of the files are shown in the table below. Notice that the use of the #include directives in each file is correct: for example, the BlinkingText.cpp file must include both the Frame.h and the Message.h header files because objects of both of these classes are declared. Also, the Location.h header file must be included by both the Frame.h file and the Message.h file because a Location object is a parameter to one or more of the methods in these files.

#include "Frame.h"
#include "Message.h"
Frame window(...);
Message greeting(...);
#include "Location.h"
class Frame
 void MoveTo(Location loc);
#include "Location.h"

class Message
 void MoveTo(Location loc);

The problem of multiple definitions arises when the preprocessor scans the BlinkingText.cpp file; in this case the preprocessed output presented to the compiler will contain the following class definitions:

           Location, Frame, Location, Message

The Location class appears twice because it is included by both the Frame.h file and the Message.h file.

Use of preprocessor variables will prevent duplicate class definitions. These variables help the preprocessor understand when an included file should be written to the preprocessor's output file or when the included file has already been written to the output file and should not be written again. A preprocessor variable is denoted by any string of characters, and for our purposes here, a preprocessor variable is either undefined (not currently known to the preprocessor) or defined (currently known to the preprocessor). Preprocessor variables that are defined may also have values attached to them, but how and why this is done is not relevant here. The preprocessor variables have nothing to do with the variables that are in the C++ code itself; they are simply names that are used during the preprocessing.

A preprocessor variable is defined by the preprocessor directive #define variablename. Any variable that has not been defined is undefined. Whether a variable is defined or not can be tested by another preprocessor directive, #ifndef variablename, which is true if the variable name is not defined and false otherwise, and a directive, #endif, that delimits the extent of the #ifndef. The preprocessor reacts to this directive in the following ways:

  • if the #ifndef is true, then continue placing the lines of the file being scanned in the output file
  • if the #ifndef is false, then skip all lines of the file being scanned until an #endif is found

These three preprocessor directives (#define, #ifndef, and #endif) are used in a standard pattern to avoid the duplication of class definitions as shown for the Location.h file in the table below. Notice that the preprocessor variable has the rather strange name" _LOCATION_H". In standard practice the name of the preprocessor variable is some variation of the file name. This standard practice makes it easy to uniquely define each preprocessor variable, since there is only one file with a given name.

Location.h File
with Preprocessor Directives
#ifndef _LOCATION_H
#define _LOCATION_H
class Location
   ... // class definition


This usage causes the preprocessor to act in the following way:

  • The first time the file is included the preprocessor variable (_LOCATION_H) will not be defined. As a result, all of the lines of the file except other preprocessor commands are processed and sent to the output file. Thus, the definition of the Location class will be written to the output file. One of the preprocessor commands encountered during this processing is the #define command that defines the preprocesor variable. In this case the #endif directive has no effect and is not copied to the output file.
  • The second time (and all subseqent times) the file is included the preprocessor variable (_LOCATION_H) will be defined. As a result, the preprocessor will ignore (not copy to the output file) all lines of the file until an #endif directive is encountered. Thus, the definition of the Location class is not duplicated in the output of the preprocessor.

After a little practice it becomes automatic to include these preprocessor directives in all header files.



  1. For the compiler that you are using, find out how to run the preprocessor and save the output produced by it. There are usually options, settings, or flags that allow this to be done. Run the preprocessor using one of the sample programs or a program that you wrote for an earlier exercise. Notice what has been included and in what order. Can you explain what you see in this output?

  2. Temporarily remove the #ifndef, #define, and #endif directives from the Location.h file and try to compile a program that would cause this header file to be included more than once. What is the error message that you get? Replace the three directives and recompile the program to be sure that you have replaced them correctly.

  3. Suppose that the preprocessor is told to scan file A and that:
    1. File A includes file B, then contains some text, A1, then includes file C, then contains some text, A2
    2. File B includes file D, then contains some text, B1
    3. File C contains some text, C1, then include file E, then contains some text, C2
    4. File D contains only text, D1
    5. File E contains only text E1

    In what order would the text appear in the preprocessor output file?


©1998 Prentice-Hall, Inc.
A Simon & Schuster Company
Upper Saddle River, New Jersey 07458

Legal Statement