Using iostreams Classes Borland provides a full implementation of the C++ input and output classes, commonly known as iostreams. With the arrival of C++ and object-oriented design, input and output operations became encapsulated in a series of classes. Each iostreams class encapsulates some form of input, output, or input and output from low-level character transfer to higher-level, file-oriented input/output operations. Stream input/output in C++ (commonly referred to as iostreams, or just streams) provides all the functionality of the stdio library in ANSI C and much more. Iostreams are used to convert typed objects into readable text, and vice versa. Streams can also read and write binary data. The C++ language lets you define or overload I/O functions and operators that are then called automatically for corresponding user-defined types. What is a stream? A stream is an abstraction referring to any flow of data from a source (or producer) to a sink (or consumer). We also use the synonyms extracting, getting, and fetching when speaking of inputting characters from a source; and inserting, putting, or storing when speaking of outputting characters to a sink. Classes are provided that support console output (constrea.h), memory buffers (iostream.h), files (fstream.h), and strings (strstrea.h) as sources or sinks (or both). The iostream library The iostream library has two parallel families of classes: those derived from streambuf, and those derived from ios. Both are low-level classes, each doing a different set of jobs. All stream classes have at least one of these two classes as a base class. Access from ios-based classes to streambuf-based classes is through a pointer. The streambuf class The streambuf class provides an interface to memory and physical devices. streambuf provides underlying methods for buffering and handling streams when little or no formatting is required. The member functions of the streambuf family of classes are used by the ios-based classes. You can also derive classes from streambuf for your own functions and libraries. The buffering classes conbuf, filebuf, and strstreambuf are derived from streambuf. Class streambuf and its dervied classes The ios class The class ios (and hence any of its derived classes) contains a pointer to a streambuf. It performs formatted I/O with error-checking using a streambuf. For example, the ifstream class is derived from the istream and fstreambase classes, and istrstream is derived from istream and strstreambase. This diagram is not a simple hierarchy because of the generous use of multiple inheritance. With multiple inheritance, a single class can inherit from more than one base class. (The C++ language provides for virtual inheritance to avoid multiple declarations.) This means, for example, that all the members (data and functions) of iostream, istream, ostream, fstreambase, and ios are part of objects of the fstream class. All classes in the ios-based tree use a streambuf (or a filebuf or strstreambuf, which are special cases of a streambuf) as its source and/or sink. C++ programs start with four predefined open streams, declared as objects of withassign classes as follows: extern istream_withassign cin;   // Corresponds to stdin; file descriptor 0. extern ostream_withassign cout;  // Corresponds to stdout; file descriptor 1. extern ostream_withassign cerr;  // Corresponds to stderr; file descriptor 2. extern ostream_withassign clog;  // A buffered cerr; file descriptor 2. Class ios and its dervied classes Stream output Stream output is accomplished with the insertion (or put to) operator, <<. The standard left shift operator, <<, is overloaded for output operations. Its left operand is an object of type ostream. Its right operand is any type for which stream output has been defined (that is, fundamental types or any types you have overloaded it for). For example, cout << "Hello!\n"; writes the string "Hello!" to cout (the standard output stream, normally your screen) followed by a new line. The << operator associates from left to right and returns a reference to the ostream object it is invoked for. This allows several insertions to be cascaded as follows: int i = 8; double d = 2.34;   cout << "i = " << i << ", d = " << d << "\n"; This will write the following to standard output: i = 8, d = 2.34 Fundamental types The fundamental data types directly supported are char, short, int, long, char* (treated as a string), float, double, long double, and void*. Integral types are formatted according to the default rules for printf (unless you've changed these rules by setting various ios flags). For example, the following two output statements give the same result: int i; long l; cout << i << " " << l; printf("%d %ld", i, l); The pointer (void *) inserter is used to display pointer addresses: int i; cout << &i;         // display pointer address in hex I/O formatting Formatting for both input and output is determined by various format state flags contained in the class ios. The flags are read and set with the flags, setf, and unsetf member functions. Output formatting can also be affected by the use of the fill, width, and precision member functions of class ios. Manipulators A simple way to change some of the format variables is to use a special function-like operator called a manipulator. Manipulators take a stream reference as an argument and return a reference to the same stream. You can embed manipulators in a chain of insertions (or extractions) to alter stream states as a side effect without actually performing any insertions (or extractions). Parameterized manipulators must be called for each stream operation. For example, #include  #include   // Required for parameterized manipulators. int main(void) { int i = 6789, j = 1234, k = 10;   cout << setw(6) << i << j << i << k << j;   cout << "\n";   cout << setw(6) << i << setw(6) << j << setw(6) << k;   return(0); } produces this output: 678912346789101234 6789  1234    10 setw is a parameterized manipulator declared in iomanip.h. Other parameterized manipulators, setbase, setfill, setprecision, setiosflags and resetiosflags, work in the same way. To make use of these, your program must include iomanip.h. You can write your own manipulators without parameters: #include  // Tab and prefix the output with a dollar sign. ostream& money( ostream& output) {   return output << "\t$";   } int main(void) {   float owed = 1.35, earned = 23.1;   cout << money << owed << money << earned;   return(0);   } produces the following output: $1.35   $23.1 The non-parameterized manipulators dec, hex, and oct (declared in iostream.h) take no arguments and simply change the conversion base (and leave it changed): int i = 36; cout << dec << i << " " << hex << i << " " << oct << i << endl; cout << dec;  // Must reset to use decimal base. // displays 36 24 44 Stream manipulators Manipulator Action dec Set decimal conversion base format flag. hex Set hexadecimal conversion base format flag. oct Set octal conversion base format flag. ws Extract whitespace characters. endl Insert newline and flush stream. ends Insert terminal null in string. flush Flush an ostream. setbase(int n) Set conversion base format to base n (0, 8, 10, or 16). 0 means the default: decimal on output, ANSI C rules for literal integers on input. resetiosflags(long f) Clear the format bits specified by f. setiosflags(long f) Set the format bits specified by f. setfill(int c) Set the fill character to c. setprecision(int n) Set the floating-point precision to n. setw(int n) Set field width to n. The manipulator endl inserts a newline character and flushes the stream. You can also flush an ostream at any time with ostream << flush; Filling And Padding The fill character and the direction of the padding depend on the setting of the fill character and the left, right, and internal flags. The default fill character is a space. You can vary this by using the function fill: int i = 123; cout.fill('*'); cout.width(6); cout << i;          // display ***123 The default direction of padding gives right-alignment (pad on the left). You can vary these defaults (and other format flags) with the functions setf and unsetf: int i = 56; . . . cout.width(6); cout.fill('#'); cout.setf(ios::left,ios::adjustfield); cout << i;          // display 56#### Stream input Stream input is similar to output but uses the overloaded right shift operator, >>, known as the extraction (get from) operator or extractor. The left operand of >> is an object of type class istream. As with output, the right operand can be of any type for which stream input has been defined. By default, >> skips whitespace (as defined by the isspace function in ctype.h), then reads in characters appropriate to the type of the input object. Whitespace skipping is controlled by the ios::skipws flag in the format state's enumeration. The skipws flag is normally set to give whitespace skipping. Clearing this flag (with setf, for example) turns off whitespace skipping. There is also a special "sink" manipulator, ws, that lets you discard whitespace. Consider the following example: int i; double d; cin >> i >> d; When the last line is executed, the program skips any leading whitespace. The integer value (i) is then read. Any whitespace following the integer is ignored. Finally, the floating-point value (d) is read. For type char* (treated as a string), the effect of the >> operator is to skip whitespace and store the next (non-whitespace) characters until another whitespace character is found. A final null character is then appended. Care is needed to avoid "overflowing" a string. You can alter the default width of zero (meaning no limit) using width as follows: char array[SIZE]; cin.width(sizeof(array)); cin >> array;            // Avoids overflow. For all input of fundamental types, if only whitespace is encountered, nothing is stored in the target, and the istream state is set to fail. The target will retain its previous value; if it was uninitialized, it remains uninitialized. I/O of user-defined types To input or output your own defined types, you must overload the extraction and insertion operators. Here is an example: #include  struct info {   char *name;   double val;   char *units;   }; // You can overload << for output as follows: ostream& operator << (ostream& s, info& m) {   s << m.name << " " << m.val << " " << m.units;   return s;   }; // You can overload >> for input as follows: istream& operator >> (istream& s, info& m) {   s >> m.name >> m.val >> m.units;   return s;   }; int main(void) {   info x;   x.name = new char[15];   x.units = new char[10];   cout << "\nInput name, value and units:";   cin >> x;   cout << "\nMy input:" << x;   return(0);   } Simple file I/O The class ofstream inherits the insertion operations from ostream, while ifstream inherits the extraction operations from istream. The file-stream classes also provide constructors and member functions for creating files and handling file I/O. You must include fstream.h in all programs using these classes. Consider the following example that copies the file FILE.IN to the file FILE.OUT: #include  int main(void) {   char ch;   ifstream f1("FILE.IN");   ofstream f2("FILE.OUT");   if (!f1) cerr << "Cannot open FILE.IN for input";   if (!f2) cerr << "Cannot open FILE.OUT for output";   while (f2 && f1.get(ch))  f2.put(ch);   return(0);   } Note that if the ifstream or ofstream constructors are unable to open the specified files, the appropriate stream error state is set. The constructors let you declare a file stream without specifying a named file. Later, you can associate the file stream with a particular file: ofstream ofile;         // creates output file stream . . . ofile.open("payroll");  // ofile connects to file "payroll" // do some payrolling... ofile.close();          // close the ofile stream ofile.open("employee"); // ofile can be reused... String stream processing The functions defined in strstrea.h support in-memory formatting, similar to sscanf and sprintf, but much more flexible. All of the istream member functions are available for class istrstream (input string stream). This is the same for output: ostrstream inherits from ostream. Given a text file with the following format: 101 191 Cedar Chest 102 1999.99 Livingroom Set Each line can be parsed into three components: an integer ID, a floating-point price, and a description. The output produced is 1: 101  191.00  Cedar Chest 2: 102  1999.99 Livingroom Set Here is the program: #include  #include  #include  #include  int main(int argc, char **argv) {    int id;    float amount;    char description[41];    if (argc == 1) {       cout << "\nInput file name required.";       return (-1);       }    ifstream inf(argv[1]);    if (inf) {       char inbuf[81];       int lineno = 0;       // Want floats to print as fixed point       cout.setf(ios::fixed, ios::floatfield);       // Want floats to always have decimal point       cout.setf(ios::showpoint);       while (inf.getline(inbuf,81)) {          // 'ins' is the string stream:          istrstream ins(inbuf,strlen(inbuf));          ins >> id >> amount >> ws;          ins.getline(description,41);  // Linefeed not copied.          cout << ++lineno << ": "             << id << '\t'             << setprecision(2) << amount << '\t'             << description << "\n";       }    }    return(0); } Note the use of format flags and manipulators in this example. The calls to setf coupled with setprecision allow floating-point numbers to be printed in a money format. The manipulator ws skips whitespace before the description string is read. Screen output streams The class constream, derived from ostream and defined in constrea.h, provides the functionality of conio.h for use with C++ streams. This lets you create output streams that write to specified areas of the screen, in specified colors, and at specific locations. As with conio.h functions, constreams are not available for GUI applications. The screen area created by constream is not bordered or otherwise distinguished from the surrounding screen. Console stream manipulators  Manipulator conio function Action clreol clreol Clears to end of line in text window. delline delline Deletes line in the text window. highvideo highvideo Selects high-intensity characters. insline insline Inserts a blank line in the text window. lowvideo lowvideo Selects low-intensity characters. normvideo normvideo Selects normal-intensity characters. setattr(int) textattr Sets screen attributes. setbk(int) textcolor Sets new character color. setclr(int) textcolor Sets the color. setcrsrtype(int) _setcursortype Selects cursor appearance. setxy(int, int) gotoxy Positions the cursor at the specified position. #include  int main(void) {    constream win1;    win1.window(1, 1, 40, 20); // Initialize the desired space.    win1.clrscr();             // Clear this rectangle.    // Use the parameterized manipulator to set screen attributes.    win1 << setattr((BLUE<<4) | WHITE)         << "This text is white on blue.";    // Use this parameterized manipulator to specify output area.    win1 << setxy(10, 10)         << "This text is in the middle of the window.";    return(0);    } You can create multiple constreams, each writing to its own portion of the screen. Then, you can output to any of them without having to reset the window each time. #include  int main(void) {    constream demo1, demo2;    demo1.window( 1, 2, 40, 10 );    demo2.window( 1, 12, 40, 20 );    demo1.clrscr();    demo2.clrscr();    demo1 << "Text in first window" << endl;    demo2 << "Text in second window" << endl;    demo1 << "Back to the first window" << endl;    demo2 << "And back to the second window" << endl;    return(0);    }