·
Separate
Compilation Larger C++ programs generally designed such that they are broken
down into smaller files that are compiled separately and linked together.
o
Header File
Each class definition should exist in a separate header file and have a
descriptive name that is associated with the class, e.g., hello.hpp or hello.hxx,
etc ...
o
Source Files
Each class that is defined in a header file should be implemented in a separate
source file that has a descriptive name that is associated with the implementation
of the class, e.g., hello.cpp or hello.cxx, etc... The source file should include the header
file for which it is associated as well as any other predefined or user defined
header files necessary for the implementation
o
The ifndef
directive should be used in all header files so as to avoid multiple inclusions
of the header file (which can cause errors) when compiling and linking.
o
Different
compilers work differently. You should
check with your compiler to see how to perform separate compilations. For example, if you are creating a project,
all the files need to be included in the project for the compile and link to
work otherwise there can be compiler errors or unresolved externals.
//Example
// Header file hello.hpp
#ifndef _HELLO_HPP_
#define _HELLO_HPP_
class Hello
{
public:
void
sayHello() const;
};
#endif
// Source file hello.cpp
#include <iostream>
using namespace std;
#include "hello.hpp"
void Hello::sayHello() const
{
cout
<< "Hello\n";
}
// Source file example.cpp
#include "hello.hpp"
int main()
{
Hello
A;
A.sayHello();
return
0;
}
·
Namespaces A
namespace is a collection of name definitions.
It allows the programmer to define, within the namespace, code that will
be applicable to that namespace only.
o
Global Namespace
The code weve been writing so far is in the global namespace, that is, it is
not any specific namespace defined by the programmer.
o
std Namespace This is the standard namespace that weve
been using. It contains all the names
defined in the C++ library files, e.g., iostream.
o
A using
directive makes all names in a namespace
available, e.g., using
namespace std;
o
A using
declaration makes only one name in the namespace available, e.g., using std::cin;
// Creating a namespace
(Example)
// Header File hello.hpp
#ifndef _HELLO_HPP_
#define _HELLO_HPP_
namespace greeting1
{
void
greeting();
}
namespace greeting2
{
void
greeting();
}
namespace greeting3
{
void
greeting();
}
#endif
// Source File hello.cpp
#include <iostream>
using namespace std;
#include "hello.hpp"
namespace greeting1
{
void
greeting()
{
cout
<< "Hello\n";
}
}
namespace greeting2
{
void
greeting()
{
cout
<< "Greetings\n";
}
}
namespace greeting3
{
void
greeting()
{
cout
<< "Welcome\n";
}
}
// Source File example.cpp
#include "hello.hpp"
int main()
{
{
using
namespace greeting1;
greeting();
}
using
greeting2::greeting;
greeting();
{
using
greeting3::greeting;
greeting();
}
return
0;
}
// Output
Hello
Greetings
Welcome
·
Streams and File
Input/Output (I/O)
o
A stream can be
thought of as a flow of characters to or from the program.
§
If the characters
are flowing into the program, the stream is called an input stream
§
If the characters
are flowing out of the program, the stream is called an output stream
o
Input and Output
Streams can be connected to files to provide a means of performing File I/O
§
Once a file is
opened, the input or output is performed similar to the way we do input from
the keyboard and output to the monitor
§
When a file is
opened, you should check to make sure that the open was successful. Use the member function fail() to check the Boolean condition.
// Example
#include
<iostream>
#include
<fstream>
#include
<cstdlib>
#include
<string>
using
namespace std;
int
main()
{
ifstream inStream1, inStream2, inStream3;
ofstream
outStream1("file1.txt"), outStream2, outStream3;
string fName;
int number, currentNumber, sum = 0;
char fileName[80];
// Check to see if file1.txt opened
successfully
if(outStream1.fail())
{
cout << "\nCould not open
file1.txt.\n";
exit (1);
}
// Write the numbers 0-9 into file1.txt
for(number = 0; number < 10; number++)
outStream1 << number <<
endl;
outStream1.close();
// Open file1.txt for reading
inStream1.open("file1.txt");
if(inStream1.fail())
{
cout << "\nCould not open
file1.txt.\n";
exit (1);
}
cout << "Enter name for Output
File 2: ";
cin >> fileName;
outStream2.open(fileName);
if(outStream2.fail())
{
cout << "\nCould not open
" << fileName << endl;
exit (1);
}
// Read the numbers in file1.txt and
calculate the sum.
// Copy file1.txt to Output File 2.
for(number = 0; number < 10; number++)
{
inStream1 >> currentNumber;
sum += currentNumber;
outStream2 << currentNumber
<< endl;
}
inStream1.close();
outStream2.close();
// Get name for output file #3 and open
it.
cout << "Enter name for Output
File 3: ";
cin >> fName;
outStream3.open(fName.c_str()); // NOTE:
Only C-Strings allowed
if(outStream3.fail())
{
cout << "\nCould not open
" << fName << endl;
exit (1);
}
// Write the sum calculated for file1.txt
// into the file just opened.
outStream3 << sum << endl;
outStream3.close();
// Display the contents of Output File 1
!!!
inStream1.open("file1.txt");
if(inStream1.fail())
{
cout << "\nCould not open
file1.txt.\n";
exit (1);
}
cout << "Contents of
file1.txt\n";
while(inStream1 >> currentNumber)
cout << currentNumber <<
" ";
cout << endl;
inStream1.close();
// Display the contents of Output File 2
!!!
inStream2.open(fileName);
if(inStream2.fail())
{
cout << "\nCould not open
" << fileName << endl;
exit (1);
}
cout << "Contents of "
<< fileName << endl;
while(!inStream2.eof())
{
inStream2 >> currentNumber;
cout << currentNumber <<
" ";
}
cout << endl;
inStream2.close();
// Display the contents of Output File 3
!!!
inStream3.open(fName.c_str());
if(inStream3.fail())
{
cout << "\nCould not open
" << fName << endl;
exit (1);
}
cout << "Contents of "
<< fName << endl;
while(inStream3 >> currentNumber)
cout << currentNumber <<
" ";
cout << endl;
inStream3.close();
return 0;
}
// Output
Enter name for Output File 2: the_copy.txt
Enter name for Output File 3: the_sum.txt
Contents of file1.txt
0 1 2 3 4 5 6 7 8 9
Contents of the_copy.txt
0 1 2 3 4 5 6 7 8 9 9
Contents of the_sum.txt
45
Question: Why does the output for the_copy.txt have an additional 9?
Is it an exact copy? To answer
the second question first, the file is an exact copy. The reason why the additional 9 is displayed
is due to the fact the I used the eof() member
function for inStream2. The eof() member function will turn true when the next read after the EOF is attempted. Therefore, the additional 9 was printed when
the EOF was encountered and then the Boolean expression
became true when we tried to read an additional character after we encountered the EOF. Summary: Be careful and use the method that I used for inStream1 unless you have a specific reason for using the eof() member function.
o
Formatting Output
with Stream Functions Output streams connected to a file have the same member
functions as cout()
o
Use the member
function setf() to set the flags of the output stream and unsetf() to unset the flags.
The flags may be ORed together if desired. For example, we can have the following:
// To set flags, do the
following
outStream.setf(ios::fixed |
ios::showpoint | ios::right);
// To unset a flag, do the following
outstream.unsetf(ios::right);
|
FLAG |
MEANING OF FLAG SETTING |
DEFAULT |
|
ios::fixed |
Do
not write floating-point numbers in scientific notation (i.e., e-notation). |
Not
set |
|
ios::scientific |
Write
numbers in scientific notation. |
Not
set |
|
ios::showpoint |
Always
show a decimal point and trailing zeros for floating-point numbers. |
Not
Set |
|
ios::showpos |
Output
a plus sign before positive integer values. |
Not
Set |
|
ios::right |
Right-justify
the output within a given field width. |
Set |
|
ios::left |
Left-justify
the output within a given field width. |
Not
Set |
|
ios::dec |
Output
integers in decimal notation. |
Set |
|
ios::oct |
Output
integers in octal notation. |
Not
Set |
|
ios::hex |
Output
integers in hexadecimal notation. |
Not
Set |
|
ios::uppercase |
Use
upper-cased letters for hexadecimal numbers and the E used in scientific
notation. |
Not
Set |
|
ios::showbase |
Show
the base of an output number (nothing for decimal notation, leading 0 for
octal notation, and leading 0x for hexadecimal notation). |
Not
Set |
o
Saving and
Restoring Flag Settings You can save flag settings for the outStream and
restore the flag settings as follows:
// To Save the Flag Settings
long flagSettings = outStream.flags();
// To Restore the Flag Settings
outStream(flagSettings);
o
Setting Field
Width you can specify the width of a field using the member function setw(). The width
will be set the number specified for the next item that is output. If there are 5 items that you want to output
with the same width, then you must use setw() 5
times. If the output is larger than the
width specified, the width is over-run and the full item is output.
// To set the width
cout << Data:;
cout.width(5);
cout << 10 << endl;
// The code above produces the following output
Data: 10
// Note there are 3 spaces between : and 1.
o
Setting Precision
you can specify the precision of a floating point number using the member
function precision(). Any floating
point number that appears after precision is set will have significant figures
equal to the argument passed. The
precision remains in effect until it is set to another value.
// To set precision
outStream.setf(ios::fixed);
outStream.setf(ios::showpoint);
outstream.precision(3);
o
Manipulators
function that is placed after the insertion operator <<, just as if the
manipulator function call were an item to be output. To use manipulators, you must include the
header file <iomanip>.
// An example of setw() and precision() as
manipulators
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
cout.setf(ios::fixed
| ios::showpoint);
cout
<< setw(10) << "Item 1:" << setw(8) <<
"$"
<<
setw(8) << setprecision(2) << 19.95 << endl;
cout
<< setw(10) << "Item 2:" << setw(8) <<
"$"
<<
setw(8) << setprecision(2) << 349.99 << endl;
return 0;
}
// Output.
Numbers below represent white space count
// for the first line followed by the second line.
3/3
7/7 3/2
Item
1: $ 19.95
Item
2: $ 349.99
·
Recursive
Functions used when the solution to a problem can be expressed in terms of
successively applying the same solution to subsets of the problem.
o
Must be designed
so that any call of the function ultimately terminates with some piece of code
that does not depend on recursion (called base cases or stopping cases).
o
Recursion uses a
structure called a stack that is managed by the computer. The memory structure for the stack is
Last-In/First-Out (LIFO).
o
Recursive
functions usually (not always) run slower than an equivalent iterative version,
but produces code that is easier to understand.
o
Three Recursive
Properties Must be Satisfied:
§
There is no
infinite recursion, i.e., there is a stopping case or base case.
§
Each stopping
case returns the correct value for that case.
§
All cases that
involve recursion must return a correct value.
// Example for calculating a
factorial
#include
<iostream>
#include
<iomanip>
using
namespace std;
long
int factorial(int num)
{
long int result;
if(num == 0)
result = 1;
else
result = num * factorial(num - 1);
return result;
}
int
main()
{
for(int number = 0; number <= 10;
number++)
cout << setw(2) <<
number << "! = " << factorial(number) << endl;
return 0;
}
//
Output
0! = 1
1! = 1
2! = 2
3! = 6
4! =
24
5! =
120
6! =
720
7! =
5040
8! =
40320
9! =
362880
10! = 3628800
// Example for performing a
binary search on an array.
#include
<iostream>
using
namespace std;
const
int ARRAY_SIZE = 100;
int
indexOfSmallest(const int a[], int startIndex, int numberUsed)
{
int min = a[startIndex];
int indexOfMin = startIndex;
for(int index = startIndex + 1; index <
numberUsed; index++)
if(a[index] < min)
{
min = a[index];
indexOfMin = index;
}
return indexOfMin;
}
void
swapValues(int& v1, int& v2)
{
int temp;
temp = v1;
v1 = v2;
v2 = temp;
}
void
sort(int a[], int numberUsed)
{
int indexOfNextSmallest;
for(int index = 0; index < numberUsed -
1; index++)
{
indexOfNextSmallest =
indexOfSmallest(a, index,
numberUsed);
swapValues(a[index],
a[indexOfNextSmallest]);
}
}
void
search(const int a[], int first, int last,
int key, bool& found,
int& location)
{
int mid;
if(first > last)
found = false;
else
{
mid = (first + last) / 2;
if(key == a[mid])
{
found = true;
location = mid;
}
else if(key < a[mid])
search(a, first, mid - 1, key,
found, location);
else if(key > a[mid])
search(a, mid + 1, last, key,
found, location);
}
}
int
main()
{
int numbers[ARRAY_SIZE];
const int finalIndex = ARRAY_SIZE - 1;
int key, location;
unsigned int seed;
bool found;
cout << "Enter a positive
integer to provide a random number seed: ";
cin >> seed;
srand(seed);
// Fill the array with random numbers
between
// 0 and ((2 * ARRAY_SIZE) - 1)
for(int i = 0; i < ARRAY_SIZE; i++)
numbers[i] = rand() % (2 *
ARRAY_SIZE);
// Sort the array in ascending order
sort(numbers, ARRAY_SIZE);
do
{
cout << "\nEnter number
to be located (-1 to quit): ";
cin >> key;
if(key < 0)
exit(0);
search(numbers, 0, finalIndex, key,
found, location);
if(found)
cout << key <<
" is in index location "
<< location
<< endl;
else
cout << key <<
" is not in the array.\n";
} while(1);
return 0;
}
//
Example Session for seed = 258
Enter a positive integer to provide a random
number seed: 258
Enter number to be located (-1 to quit): 113
113 is in index location 59
Enter number to be located (-1 to quit): 54
54 is not in the array.
Enter number to be located (-1 to quit): 196
196 is not in the array.
Enter number to be located (-1 to quit): 0
0 is in index location 0
Enter number to be located (-1 to quit): 33
33 is in index location 17
Enter number to be located (-1 to quit): 1
1 is not in the array.
Enter number to be located (-1 to quit): -1
Press any key to continue
//
Another example session for seed = 12698
Enter a positive integer to provide a random
number seed: 12698
Enter number to be located (-1 to quit): 113
113 is not in the array.
Enter number to be located (-1 to quit): 54
54 is in index location 38
Enter number to be located (-1 to quit): 196
196 is in index location 99
Enter number to be located (-1 to quit): 0
0 is not in the array.
Enter number to be located (-1 to quit): 33
33 is in index location 22
Enter number to be located (-1 to quit): 1
1 is not in the array.
Enter number to be located (-1 to quit): -1
Press any key to continue