·       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 we’ve 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 we’ve 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 OR’ed 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

Hosted by www.Geocities.ws

1