The Structure of a C++ Program

Steven Zeil

Last modified: Jun 17, 2014

Contents:
1. Separate Compilation
1.1 Separate Compilation
2. Pre-processing
2.1 #include
2.2 Other Pre-processing Commands
3. Declarations and Definitions
3.1 Decls&Defs: Variables
3.2 Decls&Defs: Functions
3.3 Decls&Defs: Data Types
4. Modules
4.1 Coupling and Cohesion
5. Example of Modularization: the auction program
5.1 Dividing Things Up

1. Separate Compilation

Working with Large Programs


Single File Programs

Putting your entire program into a single file is


Multiple File C++ Programs

By splitting a program up into multiple files that can be separately,

1.1 Separate Compilation

Object Code

Linking

Linking mainly consists of replacing symbols by real addresses.

On large projects with hundreds to thousands of files,

2. Pre-processing

The # Preprocessor

The preprocessor runs before the compiler proper.

The preprocessor:


Pre-Processor Instructions

The common pre-processor instructions are

2.1 #include

Example: #include (simple case)}

A.h

B.h

C.cpp

g++ -E C.cpp > C.i

C.i.listing

A more realistic example

In real programs, most of the code actually seen by the compiler may come from #includes

#include <iostream>

using namespace std;

int main() {
  cout << "Hello World" << endl;
  return 0;
}

Deja-Vu

This distinction will be important later.

2.2 Other Pre-processing Commands

#define

#define VersionNumber "1.0Beta1"

int main() {
   cout << "Running version "
        << VersionNumber
        << endl;

#ifdef, #ifndef, #endif

Used to select code based upon whether a macro has been defined:

#ifdef __GNUG__
  /* Compiler is gcc/g++ */
#endif
#ifdef _MSC_VER
  /* Compiler is Microsoft Visual C++ */
#endif


#if, #define, and #include

A2.h

,

B2.h

,

C2.cpp

g++ -E C2.cpp > C2.i


Shorter Translation Unit

The result is file C2.i.

3. Declarations and Definitions

Common Errors


Declarations

A declaration in C++


Definitions

A definition in C++


General Rules for Decls & Defs

3.1 Decls&Defs: Variables

3.2 Decls&Defs: Functions

3.3 Decls&Defs: Data Types

4. Modules

Organizing Decls & Defs into Files


Headers and Compilation Units

A typical C++ program is divided into many source code files


Can You See Me Now?…Now?…Now?

How often does the compiler process each line of code from a file?

Therefore a header file can only contain things that can legally appear multiple times in a C++ program –


Division: headers and compilation units

4.1 Coupling and Cohesion


Coupling

highCoupling

Something with high coupling has many dependencies on external entities

lowCoupling

Something with low coupling has few dependencies on external entities


Cohesion

foldingKnife

s_screwdriver1

In something with high cohesion, all the pieces contribute to a well-defined, common goal.

swissArmy

In something with low cohesion, the pieces have little relation to one another


Extremely Low Cohesion

gig-swiss-knife


Dividing into modules

  • How do we divide up the compilation units?

  • Usually pair them up with a header

    • one compilation unit for each header file

    • The compilation unit provide definitions for each declaration in the header that is it paired with.

  • Such pairs are a one of the most common forms of module

    • a group of related source code files

5. Example of Modularization: the auction program

Read this description of the auction program. It’s an example that we will use over and over throughout the semester.

The overall algorithm is pretty simple

main (fileNames[]){
  readItems;
  readBidders;
  readBids;
  for each item {
    resolveAuction (item, bidders, bids)
  }
}

We read in all the information about the auction, then resolve the bidding on each item, one at a time (in order by closing time of the bidding for the items).


The Auction Program before Modularization

We could implement that in one file:

auction1File.cpp

… but it would not be a very good idea.

The details of the code for each function body really aren’t important right now (with a slight exception that I’ll get into later). The most important thing during modularization is to know what the functions and data are and what role they play in the program.


A Possible Modularization

From the description of the program and from a glance through the code, we might guess that the key modules would be

Items
Data and functions related to the items up for auction
Bidders
Data and functions related to the people bidding in the auction
Bids
Data and functions related to the bids placed by those people
Money
Data and functions related to money
Time
Data and functions related to time.

(In later lessons we’ll talk about other ways to identify good modules.)


Module Files

And we would then expect to divide the program into files corresponding to those modules:

  • Group everything describing the items into items.h and items.cpp.

  • Group everything describing the bidders into bidders.h and bidders.cpp.

  • Group everything describing the bids into bids.h and bids.cpp.

  • Group everything for manipulating times into times.h and times.cpp.

  • Group everything for manipulating money into money.h and money.cpp.

  • Put the main program and the core auction algorithm into auctionMain.cpp.


Making a List …

If we then make a list of the data …

Types Data
Money bidders
Time bids
Bid items
Bidders
Item
BidSequence
BidderSequence
ItemSequence

Making a List …

… and of a list of the functions in this program …

Types Data Functions
Money bidders add
Time bids equal
Bid items findBidder
Bidders lessThan
Item noLaterThan
BidSequence print (money)
BidderSequence print (time)
ItemSequence read (bid)
read (bid sequence)
read (bidder)
read (bidder sequence)
read (item)
read (item sequence)
read (money)
read (time)
resolveAuction
subtract

… and Checking It (at least twice)

… then we can pretty much assign these to our modules just by

  • reading their names and, in a few cases,

  • looking at the comments in the code that describe them:

Bids
Bid, BidSequence, bids, read bid, read bid seq.
Bidders
Bidder, BidderSequence, bidders, findBidder, read bidder, read bidder seq.
Items
Item, ItemSequence, items, read item, read item seq.
Money
Money, add, equal, lessThan, print, read, subtract
Time
Time, noLaterThan, print, read
??
resolveAuction, main

The “application”

The final two functions, resolveAuction and main, constitute the core algorithm, the “main application” for this particular program, and so can be kept in the main cpp file.

5.1 Dividing Things Up

We can now prepare the modular version of this program.

  • By default, each function or variable that we have identified gets
    • declared in its module’s header file and
    • defined in its module’s implementation file.

Headers are for Sharing

We can reduce possible coupling, though, by looking at the actual function bodies and

  • checking to see if any of these declarations would only be used internally within a single module.
    • A declaration only needs to appear in the header file if some code outside the module is using it.
    • If it is only used from within its own module. it can be kept “hidden” inside that module’s .cpp file.

Not Shared

For example, in the Items module, the function read that reads a single item is only called from inside the function read that reads an entire sequence of items.

  • Because that first read is only called by a function within its own module, it does not need to be listed in items.h.

Possible Division

  • Bids

auction/bids.h

auction/bids.cpp

  • Bidders

auction/bidders.h

auction/bidders.cpp

  • Items

auction/items.h

auction/items.cpp

  • Money

auction/money.h

auction/money.cpp

  • Time

auction/times.h

auction/times.cpp


Main Auction Program

auction/auctionMain.cpp