Table of Contents
C++ programs can range from a handful of statements to hundreds of thousands
May be written by one person or by a team
OK for small programs (CS150)
But with large programs
compilation would take minutes, hours, maybe days
might break compiler
Team members would interfere with one another’s work.
"Are you still editing that file? You've had it all afternoon."
"What do you mean you're saving changes to the file? I've been editing it for the last 45 minutes!"
By splitting a program up into multiple files that can be compiled separately,
Team members can work in parallel on separate files
Files are compiled separately
each individual compilation is fast
Separately compiled code is linked to produce the executable
linking is much faster than compilation
Each file of source code
programming language text
is compiled to produce a file of object code
binary code, almost executable
exact addresses of variables and functions not known, represented by symbols
All object code files are linked to produce the executable
Linking mainly consists of replacing symbols by real addresses.
On large projects with hundreds to thousands of files,
Typically only a few files are changed on any one day
Often only the changed files need to be recompiled
Then link the changed and unchanged object code
The preprocessor runs before the compiler proper. The preprocessor:
modifies the source code
processes preprocessor instructions
lines beginning with #
strips out comments
The common pre-processor instructions are
#include
insert a file
#define
define a macro
#ifdef, #ifndef, #endif
check to see if a macro has been defined
Inserts a file or header into the current source code
Two versions
#include <headerName>
inserts a system header file from a location defined when the compiler was installed
#include "fileName"
inserts a file from the current directory
Example 2. #include (realistic case)
In real programs, most of the code actually seen by the compiler
may come from #include
s
Used to define macros (symbols that the preprocessor will later substitute for)
Sometimes used to supply constants
#define VersionNumber "1.0Beta1" int main() { cout << "Running version " << VersionNumber << endl;
Much more elaborate macros are possible, including ones with parameters
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
All of these macros are used to reduce the amount of code seen by the actual compiler
We ask the compiler to only run the preprocessor and save the result:
g++ -E C2.cpp > C2.i
The result is file C2.i
Note that the code from A2.h
is
included only once
Imagine now, if that were iostream
instead of A2.h
Some of the most common error messages are
… is undeclared
… is undefined
… is defined multiple times
Fixing these requires that you understand the difference between declarations and definitions
and how they relate to the program structure
A declaration in C++
introduces (or repeats) a name for something
tells what “kind” of thing it is
gives programmers enough information to use it
A definition in C++
introduces (or repeats) a name for something
tells what “kind” of thing it is
tells what value it has and/or how it works
gives the compiler enough information to generate this and assign it an address
All definitions are also declarations.
But not vice versa
A name must be declared before you can write any code that uses it.
A name can be declared any number of times, as long as the declarations are identical.
A name must be defined exactly once, somewhere within all the separately compiled files making up a program.
These are definitions of variables:
int x; string s = "abc"; MyFavoriteDataType mfdt (0);
These are declarations:
extern int x; extern string s; extern MyFavoriteDataType mfdt;
Declaration:
int myFunction (int x, int y);
Definition
int myFunction (int x, int y) { return x + y; }
The declaration provides only the header. The definition adds the body.
A C++ program consists of declarations and definitions.
These are arranged into files that are combined by
linking after separate compilation
#include'ing one file into another
These arrangements must satisfy the general rules:
A name must be declared before you can write any code that uses it.
A name can be declared any number of times, as long as the declarations are identical.
A name must be defined exactly once, somewhere within all the separately compiled files making up a program.
A typical C++ program is divided into many source code files
Some are headers
Typically end in ".h"
May be #include
d from many different
places
May #include
other headers
Not directly compiled
The non-header files
Typically end in ".cpp", ".cc", or ".C"
Should never be #include
d from
elsewhere
May #include
headers
Are directly compiled
How often does the compiler process each line of code from a file?
For headers, any number of times
For non-headers, exactly once
Therefore a header file can only contain things that can legally appear multiple times in a C++ program - declarations
Header files may contain only declarations
specifically, declarations that need to be shared with different parts of the code
Non-headers may contain declarations and definitions
Definitions can only appear in a non-header.
Never, ever, ever
#include
a non-header (.cpp) file
How do we divide things into different headers?
Identify groups of declarations with
Low coupling - dependencies on other groups
High cohesion - dependencies within the group
Something with high coupling has many dependencies on external entities
Something with low coupling has few dependencies on external entities
In something with high cohesion, all the pieces contribute to a well-defined, common goal.
In something with low cohesion, the pieces have little relation to one another
How do we divide up the non-header source files?
Usually pair them up with a header
one non-header file for each header file
The non-header file 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
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 full implementation is shown here, but to the right I show a simplified version. 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.
From the description of the program and from a glance through the code, we might guess that the key modules that we can come up with would be:[1]
Data and functions related to the items up for auction
Data and functions related to the people bidding in the auction
Data and functions related to the bids placed by those people
If we then make a list of the functions and data in this program:
Functions | Data |
---|---|
printTime | nItems |
noLaterThan | MaxItems |
readBidders | itemNames |
readItem | itemReservedPrice |
readItems | itemEndHours |
findBidder | itemEndMinutes |
readBids | itemEndSeconds |
resolveAuction | nBidders |
main | MaxBidders |
bidderNames | |
bidderBalances | |
nBids | |
MaxBids | |
bidBidder | |
bidAmounts | |
bidItems | |
bidHours | |
bidMinutes | |
bidSeconds |
then we can pretty much assign these to our modules just be reading their names and, in a few cases, looking at the comments in the code that describe them:
Module | Functions | Data |
---|---|---|
Items | readItem | nItems |
readItems | MaxItems | |
itemNames | ||
itemReservedPrice | ||
itemEndHours | ||
itemEndMinutes | ||
itemEndSeconds | ||
Bidders | readBidders | nBidders |
findBidder | MaxBidders | |
bidderNames | ||
bidderBalances | ||
Bids | readBids | nBids |
MaxBids | ||
bidBidder | ||
bidAmounts | ||
bidItems | ||
bidHours | ||
bidMinutes | ||
bidSeconds | ||
??? | resolveAuction | |
noLaterThan | ||
printTime | ||
main |
We have a few functions still unassigned. Looking at them, the
functions printTime
and noLaterThan
are both
concerned with handling "time", which suggests that a new "Time" module
might be in order. The final two functions, resolveAuction
and main
, constitute the core algorithm, the "main
controller" for this particular program, and so can be kept in the main
cpp file. So our final division looks like:
Module | Functions | Data |
---|---|---|
Items | readItem | nItems |
readItems | MaxItems | |
itemNames | ||
itemReservedPrice | ||
itemEndHours | ||
itemEndMinutes | ||
itemEndSeconds | ||
Bidders | readBidders | nBidders |
findBidder | MaxBidders | |
bidderNames | ||
bidderBalances | ||
Bids | readBids | nBids |
MaxBids | ||
bidBidder | ||
bidAmounts | ||
bidItems | ||
bidHours | ||
bidMinutes | ||
bidSeconds | ||
Time | noLaterThan | |
printTime | ||
(main) | resolveAuction | |
main |
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.
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 declarion 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.
For example, in the Items
module, the function readItem
, which reads a single item,
is only called from inside the function readItems
, which
reads an entire array of items. Because readItem
is only
called by a function within its own module, it does no need to be listed
in items.h
.
Main program with core auction algorithm: auction/auctionMain.cpp,
Discuss This Page: