C++ Streams

- We’ve seen how C I/O (input/output) routines (printf, scanf) can be used in C++ programs
- This is perfectly valid since C is a subset of C++
- In addition to the C I/O routines, C++ supports a more object-oriented I/O facility
- This facility uses features of object-oriented programming such as overloading and inheritance
- Not a built-in system to C++, rather part of a standard library (of classes)
 

Stream

- A stream can be defined simply as a flow of data (sequence of bytes) between devices
- In input operations, bytes flow from some device (i.e. keyboard, disk, network, ...) to memory
- In output operations, bytes flow from memory to some device (i.e. screen, disk, network, printer, ...)

 

 

C++ Standard Library

- A stream can be ideally described with a C++ class (knows about data flow, does data flow)

- There can be many different types of specific streams (input, output, file I/O, ...)

- The C++ standard library includes such classes for use in C++ programs

- These are classes (stored in a library) that were written by other developers

- These classes assist C++ programmers with I/O streaming functionality

- In addition to streams, the C++ standard library contains many other useful features

- As we’ll see in detail later, such features include templates, data structures, and algorithms
 

 

Stream Operators
- C++ stream classes employ the use of overloaded operators for I/O processing as in the following example

 

cout << “Hello”;

 

- We know (from overloading studies), that a function is associated with the << operator when processed

- The operators << and >> (chosen by the class developers) are overloaded to perform stream I/O

- You might recognize that these operators are also used in C to shift individual bits

- When used with C++ streams, however, they are overloaded to perform a different task

- This dual usage (bit operators and I/O streams) is one of the unique features of overloading

- With C++ streams, the >> operator performs input and the << operator performs output
- In C++,
<< and >> are also referred to as the stream insertion and stream extraction operators

- Which class contains the overloaded << function called when the statement above is processed?

- Recall that the operands of such a statement are used to determine the appropriate overloaded function

- For example, the operand associated with the addition operator below is a Fraction object

 

Fraction f1;

f1 + 2;

 

- The Fraction class must contain the operator function to define how to add an integer to a Fraction

- Our C++ output statement (repeated below) is examined in the exact same manner

 

cout << “Hello”;

 

- In this case, the operand associated with the << operator is some class object named cout

- The class that this object belongs to contains the operator function that defines how to output a string

- The class this object belongs to is one of the C++ stream classes included in the standard library

- Note how we can use this object named cout without defining it as is necessary with other variables

- Let’s look a bit more closely into this and other previously defined class objects

 

 

Stream Objects

- The variable cout in the statement above is a predefined object from one of the C++ stream classes

- This and other stream objects are externally defined in the C++ stream class header files

- We’ve seen how C++ streams are implemented in a standard library of supplied classes
- As with our classes, header files containing the class declarations must be included in programs

- To use C++ stream classes, we must include the appropriate header files in our programs

- The standard library organizes its class declarations in the header files described below

- Included with the class declarations are external definitions for the stream objects (cout, cin, cerr)

- It is important to recognize that these are simply objects from different C++ stream classes

- Note how the “.h” extension is no longer necessary for C++ standard library classes

 

<iostream>
Declares basic services required for all stream-I/O operations
Externally defines the following stream objects

 

Stream Object

Description

C equivalent

cin

Standard input

stdin

cout

Standard output

stdout

cerr

Standard error

stderr

 

 

<iomanip>
Declares services useful to perform formatted I/O

 

<fstream>
Declares services for file processing operations

 

 

 

Using Stream Objects

- Stream operators work with built-in types (int, float, char)
- Associated with each of the built-in types, are functions overloading the
<< and >> operators
- These functions provide the appropriate conversion from type to a string (output) and string to a type (input)
- This is similar to how conversions are implement in C (
printf( "%0.4f", tmp) )
- Compare the syntax used for streams in C and C++:
 

C

C++

 

 

/* standard I/O */

// C++ stream I/O

 

 

#include <stdio.h>

#include <iostream>

 

using namespace std; 

main()

main()

{

{

    int x;

    int x;

    scanf( "%d", &x );

    cin >> x;

    printf( "%d\n", x );

    cout << x << endl;

}

}


 

- Note the use of the special stream manipulator endl to indicate a new line in a stream

- Note the inclusion of the following statement

 

using namespace std; 

 

- This instructs the compiler to use specific naming conventions used in the C++ standard library (std)

- As we’ll see later, this statement uses a feature included in the standard library called a namespace

- Without this statement, the compiler will not recognize cout, cin and endl

- Stream objects can be used to process I/O in a very elegant manner as in the following example

 

#include <iostream>

using namespace std;

 

main()

{

  float price;

  int qty;

 

  cout << "Enter part quantity: ";

  cin >> qty;

  cout << "Enter price of part: $";

  cin >> price;

  cout << "Total order comes to : $" << qty * price << endl;

 

Output
Enter part quantity: 5

Enter price of part: $10

Total order comes to : $50

- Note how stream operators can be chained together as in the last statement
- Note also that there exists a default conversion of the built-in types to strings in output
- To customize output format, C++ provides facilities for user-specified formatting
 
 

Stream Formatting
- cin and cout use default formatting defined in overloaded operator methods
- Using special I/O manipulators, we can specify a wide variety of custom formatting

- I/O manipulators, part of the C++ I/O stream library, are used with the header file, iomanip

- In many cases, we can use either a manipulator function or an associated class member function

- Let’s look at two examples of custom formatting specifying floating-point precision and field width

- Consult the C++ reference book for a complete list of all the available formatting options

- The site cplusplus.com provides an excellent reference for streams (and other C++ resources)


 

Floating-point precision
- Sets precision for all subsequent operations
- Manipulator function: setprecision
- Member function: precision

 

#include <iostream>

using namespace std;

 

#include <iomanip>

#include <math.h>               // C math functions

 

main()

{

  float root2 = sqrt( 2.0 );

  int i;

 

  cout << "Using member method..." << endl;

  for( i = 0; i <= 9; ++i )

    {

      cout.precision( i );

      cout << root2 << endl;

    }

 

  cout << "Using manipulator..." << endl;

  for( i = 0; i <= 9; ++i )

    {

      cout << setprecision( i ) << root2 << endl;

    }

 

Output
Using member method...

1

1

1.4

1.41

1.414

1.4142

1.41421

1.414214

1.4142135

1.41421354

Using manipulator...

1

1

1.4

1.41

1.414

1.4142

1.41421

1.414214

1.4142135

1.41421354

 

 


Field Width
- Sets number of character positions in output (field width)
- If values processed are smaller, field is padded
- If values processed are larger, value is NOT truncated
- Sets field width for only the next value, set to 0 implicitly after use
- Values will be as long as they need to be with zero width
- Manipulator function: setw
- Member method: width

 

Example 1

#include <iostream>

using namespace std;

 

#include <iomanip>

 

main()

{

  int i;

  int itmp = 5;

  string str("Hello");

 

  for( i = 1; i < 10; ++i )

    {

      // Setting width with member function

      cout.width(i);

      cout << str << endl;

 

      // Width implicitly set to 0

      cout << itmp << endl;

    }

}

Output
Hello
5
Hello
5
Hello
5
Hello
5
Hello
5
 Hello
5
  Hello
5
   Hello
5
    Hello
5
 

Example 2

#include <iostream>

using namespace std;

 

#include <iomanip>

 

main()

{

 

  int i;

  int itmp = 5;

  string str( "Hello" );

 

  for( i = 1; i < 10; ++i )

    {

      // Setting width with member function

      cout.width(i);

 

      cout << str << endl;

 

      // Setting width with manipulator

      cout << setw(i) << itmp << endl;

    }

}

 

Output
Hello

5

Hello

 5

Hello

  5

Hello

   5

Hello

    5

 Hello

     5

  Hello

      5

   Hello

       5

    Hello

        5

 

 

 

Lower-Level Stream processing
- C++ streams offer a variety of methods to operate at a low-level, character-by-character basis

- In this example, we are accessing stream objects directly with member functions
- Member functions get and put are used to input and output from standard in and standard out
- No need for stream operators << and >>

#include <iostream>

using namespace std;

 

main()

{

 

  char c;

 

  // Copy until end of input is reached

  while( ( c = cin.get() ) != EOF )

    cout.put( c );

 

}

 

Output
Hello
Hello

 

Stream Objects and Strings
- cin is used to input a single element as in the following statement

int qty;

cin >> qty;

 

- This operation will skip any input leading whitespace characters (tab, space)
- This operation will stop reading input when a whitespace character is encountered
- As a result, we cannot use this operation to read elements containing whitespaces (i.e. spaces)

- Consider the following example where we only read the first name entered

 

#include <iostream>

using namespace std;

 

main()

{

 

  string name;

  cout << "Enter name (first last): ";

 

  cin >> name;

  cout << "Your name: " << name << endl;

 

}

Output
Enter name (first last): John Doe
Your name: John
 

- The stream extraction operator is reading the first element and terminates at the blank space
- If the number of elements are known, we can chain the stream extraction operator as in the modified example

 

#include <iostream>

using namespace std;

 

main()

{

  string firstName, lastName;

  cout << "Enter name (first last): ";

 

  cin >> firstName >> lastName;

  cout << "Your name: " << firstName << " " << lastName << endl;

}

Output
Enter name (first last): John Doe
Your name: John Doe

 

- How does this example work?  What do you think the operation cin >> firstName returns?
- Since the overloaded input stream operation returns the stream object, we can chain calls
- What about if we don't know the number of elements to read beforehand?

- We could either use methods associated with the string class or the C++ stream class

 
string class supplies a non-member function to read a line until a newline character

 

getline( istream arg1, string arg2, char arg3 )

arg1 - input stream, standard input would be cin
arg2 - string to load the input
arg3 - optional delimiting character, default is '\n'
 

Input stream class supplies a member function to read a line until a newline character
 

cin.getline( char arg1[arg2], int arg2, char arg3 )

arg1 - char array to load charater string
arg2 - number of characters to read
arg3 - optional delimiting character, default is '\n'

 

Example 1 - nonmember string function

 

#include <iostream>

using namespace std;

main()
{
  cout << "Enter name (first last): ";
  string name;
  getline( cin, name );

  cout << "Your name: " << name << endl;
}

Output
Enter name (first last): John Doe
Your name: John Doe
 

 

Example 2 – nonmember string function (w/ delimiting character)

 

#include <iostream>

using namespace std;

main()
{
  cout << "Enter sentence with a : character" << endl;
  string str;
  getline( cin, str, ':' );
  cout << "You entered: " << str << endl;
}

Output
Enter sentence with a : character

This is a sentence:

You entered: This is a sentence

 

 

 

Example 3 – input stream member function

 

#include <iostream>

using namespace std;

main()
{
  cout << "Enter name (first last): ";
  char name[100];
  cin.getline( name, 100 );

  cout << "Your name: " << name << endl;
}
 

Output
Enter name (first last): John Doe
Your name: John Doe
 

 

Skipping string problem
- Try two cin statements, with the second using either of the getline methods above

- Lets examine the following example

 

#include <iostream>

using namespace std;

main()
{
  int i;
  string str;
  cout << "Enter an integer: ";
  cin >> i;
  cout << "Integer is: " << i << endl;
  cout << "Enter a string: ";
  getline( cin, str );
  cout << "String is: " << str << endl;
  cin >> str;
  cout << "String is: " << str << endl;
}

Output
Enter an integer: 1
Integer is: 1
Enter a string: String is:
hello
String is: hello
 

- What is happening in this example?  Is the function getline skipping the string?
- cin will read until it sees a newline character
- cin stops before newline character (created by Enter key) and will NOT be read
- This newline character is still sitting on the input buffer waiting to be read
- The next getline statement will read this newline character
- Similarly, getline reads until a newline character
- The getline statement reads the newline and stops
- The string is now still sitting in the input buffer
- This string will be read with any subsequent input statements

- We can solve this problem by using a statement to ignore a character
- Stream class member function ignores next character in input buffer

cin.ignore()

 

- We can use this method to correct our string skipping problem above

 

#include <iostream>

using namespace std;

main()
{
  int i;
  string str;
  cout << "Enter an integer: ";
  cin >> i;
  cout << "Integer is: " << i << endl;
  cout << "Enter a string: ";
  cin.ignore();
  getline( cin, str );
  cout << "String is: " << str << endl;
}

Output
Enter an integer: 1
Integer is: 1
Enter a string: hello
String is: hello


 

File Streams
- The C++ standard library also provides C++ classes to handle streams associated with files

- These classes define operations to read and write from and to files
- File stream classes do not provide pre-defined class objects similar to
cin and cout
- Instead, we declare our own objects from file stream classes
- Use of these classes is provided with the header file
<fstream>
- Three commonly used file stream classes

 

Class Name

Function

ofstream

Open file for output only

ifstream

Open file for input only

fstream

Open file for input or output

 

Example 1

#include <iostream>

using namespace std;

 

#include <iomanip>

#include <fstream>

 

main()

{

  // Open file for output

  ofstream outFile( "copy.out", ios::out );

 

  // Standard input to output file

  cout << "Type a sentence" << endl;

 

  char c;

  while( ( c = cin.get() ) != '\n' )

    outFile.put( char(c) );

 

  outFile.close();

 

  // Open file for input

  ifstream inFile( "copy.out", ios::in );

 

  // Input file to standard out

  while( ( c = inFile.get() ) != EOF )

    cout << c;

  cout << endl;

 

  inFile.close();

Output
Type a sentence
CSC 125 is fun!
CSC 125 is fun!

- C++ stream classes, as we’ll see with inheritance, are related in a large class hierarchy

- At the top of this hierarchy is a base class (ios) which contains general functionality for all classes
-
ios::out, ios::in are enumeration constants from this base class

- These constants specify file operations (open for output, open for input)
- Could have also used stream operators with file stream objects by replacing

while( ( c = cin.get() ) != '\n' )
  outFile.put( char(c) );

with

 while( ( c = cin.get() ) != '\n' )
  outFile << c;

 

 

Example 2

#include <iostream>

using namespace std;

 

#include <fstream>

 

main()

{

 

  // Open file for output

  ofstream outFile( "copy.out", ios::out );

 

  // Standard input to output file

  cout << "Type a sentence" << endl;

 

  char c;

 

  while( ( c = cin.get() ) != '\n' )

    outFile << c;

 

  outFile.close();

 

  // Open file for input

  fstream file;

 

  file.open( "copy.out", ios::in );

 

  while( ( c = file.get() ) != EOF )

    cout << c;

 

  cout << endl;

 

  file.close();

 

}

Output
Type a sentence
CSC 125 is fun!
CSC 125 is fun!

- Note use of general fstream object
- Used for both input and output, input in our example

 


Overloading stream operators with your classes
- Finally, we can overload stream operators to use with our own classes
- We overload the stream operators (<<,>>) to provide I/O for our classes
- Overloading the output operator can replace our "Print" methods!
- Overloaded stream operators are defined in a special way for a user-defined class

// Overloaded input stream operator
istream &operator>>( istream &strm, object_type &object )
{
    // read in object information

    // return stream object (for chaining)
    return strm;
}

// Overloaded output stream operator
ostream &operator<<(ostream &strm, object_type &object)
{
    // write out object information

    // return stream object (for chaining)
    return strm;
}

- Methods require appropriate stream object as the first argument
- Second argument is the class type object to be input or output
- Note how stream object is returned to allow chaining operators

- Lets implement an overloaded output stream operator for a Point class below

- Note how the overloaded operator is implemented as a non-member friend of the Point class
 

#include <iostream>

using namespace std;

 

class Point

{

 

private:

  float x, y, z;

  float size;

 

public:

  // Constructor

  Point( float c1=0.0, float c2=0.0, float c3=0.0 )

  {

    x = c1;

    y = c2;

    z = c3;

    size = 0.0;

  }

 

  // Overloaded operator declaration - Non-member friend

  friend ostream &operator<<(ostream &strm, const Point &);

 

  // Access methods

  float setSize( float f )

  {

    size = f;

  }

 

  float getSize()

  {

    return size;

  }

 

};

 

// Overloaded output stream operator definition

ostream &operator<<(ostream &strm, const Point &t)

{

  strm << "  x, y, z: " << t.x << "," << t.y << "," << t.z << endl;

  strm << "  size: " << t.size << endl;

  return strm;

}

 

main()

{

 

  Point p(1,2,3);

 

  cout << "The point info...\n" << p;

Output
The point info...
  x, y, z: 1,2,3
  size: 0