Home | Gaming | Programming | Play Online | Contact | Keyword Query
Games++ Games & Game Programming

GAMES++
Games++ Home
Games++ Gaming
Games++ Programming
Beta Testing Games
Free Online Games
Hints & Cheats

BROWSER UTILITIES
E-mail This Page
Add to Favorites

SITE SEARCH

Web Games++

AFFILIATES
Cheat Codes
Trickster Wiki
Game Ratings
Gameboy Cheats
PlayStation Cheats
BlackBerry Games
Photoshop Tutorials
Illustrator Tutorials
ImageReady Tutorials

ADVERTISEMENT

ADVERTISEMENT

Ch 12: Advanced I/O - C++ by Metrowerks

Introduction to C++ by Metrowerks

Stream Classes

C++ contains several pre-built libraries filled with stream classes that will help you with your input and output operations.

Header Files

The and headers make up a complex hierarchy of template classes that support input and output operations. Following is a table containing the names of the template classes within the and headers:

Template Class Character-based Class Wide-Character-based Class
basic_streambuf streambuf wstreambuf
basic_ios ios wios
basic_istream istream wistream
basic_ostream ostream wostream
basic_iostream iostream wiostream
basic_fstream fstream wfstream
basic_ifstream ifstream wifstream
basic_ofstream ofstream wofstream

Table 12-1: C++ I/O headers.

Overloading I/O Operators

Throughout this course, we have worked with the input and output operators: << and >>. Respectively, they are known as the inserter operator and extractor operators. Even though they are already an overloaded operator (they overload the bit shift operators), inserters and extractors can be again overloaded.

Inserters

It is possible to create an output stream that can be used in any situation. Let's take a look at the setup for an overloaded << operator that outputs three variables of a class type samp_class:

ostream &operator<<(ostream &stream, samp_class o1) {     stream ><< o1.a << ", ";
    stream << o1.b << ", ";
    stream << o1.c << ", ";
    return stream;
}

This configuration removes the dependency on the limited cout statement and allows for any data type to be output using the << operator.

Extractors

Extractors operate the same way. Let's look at what the code would look like for an overloaded extraction operator that asks for the input of the above three variables:

istream &operator>>(istream &stream, samp_class &o1)
{
    cout << "Enter values for a, b, and c: ";
    stream >> o1.a >> o1.b >> o1.c;
    return stream;
}

It is important to note that both inserters and extractors cannot be members of the classes on which they operate. They must either be independent functions or "friends" of those classes.

Formatted I/O

All of the output that we have produced in this course so far has been done so according to the defaults of the C++ I/O system. However, it is also possible to format text and numbers using member functions of the ios class.

Formatting with the ios Member Functions

The ios class contains an enumeration of format flags called fmtflags. The following values are defined in the enumeration:

adjustfield oct
basefield right
boolalpha scientific
dec showbase
fixed showpoint
floatfield showpos
hex skipws
internal unitbuf
left uppercase

Table 12-2: ios member functions.

Let's take a look at the effects that these flags will have on a program's output. When the left flag is active, output is left-justified. When the right flag is set, output is right-justified. The default for output is right-justification for text and left-justified for numbers.

Default numeric values are output in decimal form. This standard can be changed using the hex (hexadecimal) flag or the oct (octal) flags. To return output to decimal form after a change, the dec flag is used. When the showbase flag is on, the base is indicated with a 0x for hexadecimal, or 0 for octal.

The showpos flag causes a plus sign to be displayed before all positive numbers. The showpoint flag causes a decimal point and any trailing zeros to be output for all floating point numbers. The scientific flag, when activated, causes floating-point numbers to be output in scientific notation.

The fixed flag causes floating-point values to be displayed normally. If the boolalpha flag is enabled, Boolean values will be indicated using true and false rather than 1 and 0.

The following program illustrates how these various flags are turned on and off:

#include 
using namespace std;
int main()
{
    cout.setf(ios::scientific);
    cout.setf(ios::showpos);
    cout << 8 << " " << 88.88 << '\n';
    cout.unsetf(ios::scientific);
    cout.unsetf(ios::showpos);
    cout << 8 << " " << 88.88;
    return 0;
}

The output from this program looks like this:

+8 +8.888000e+01
8 88.88

Using I/O Manipulators

There is a large set of functions contained within the header than can be used to alter the output format parameters of a stream. Review the following table of manipulators:
Manipulator Purpose Works with Input or Output
boolalpha Turns on boolalpha flag Input/Output
dec Turns on dec flag Input/Output
endl Output a newline character and flush the stream Output
ends Output a null Output
fixed Turns on fixed flag Output
flush Flush a stream Output
hex Turns on hex flag Input/Output
internal Turns on internal flag Output
left Turns on left flag Output
noboolalpha Turns off boolalpha flag Input/Output
noshowbase Turns off showbase flag Output
noshowpoint Turns off showpoint flag Output
nowshowpos Turns off showpos flag Output
noskipws Turns off skipws flag Input
nounitbuf Turns off Output
nouppercase Turns off uppercase flag Output
oct Turns on oct flag Input/Output
resetiosflags (fmtflags f) Turn off the flags specified in f Input/Output
right Turns on right flag Output
scientific Turns on scientific flag Output
setbase(int base) Set the number base to base Input/Output
setfill(int ch) Set the fill character to ch Output
setisosflag(fmtflags f) Turn on the flags specified in f Input/Output
setprecision(int p) Set the number of digits of precision Output
setw(int w) Set the field width to w Output
showbase Turns on showbase flag Output
showpoint Turns on showpoint flag Output
showpos Turns on showpos flag Output
skipws Turns on skipws flag Input
unitbuf Turns on unitbuf flag Output
uppercase Turns on uppercase flag Output
ws Skip leading white space Input

Table 12-3: I/O manipulators.

These manipulators are used within the stream. Instead of calling the setf member of the stream object, you can use:

cout << scientific << showpos << 8 << " " << 88.88 << '\n';

for the same effect.

File I/O

The C++ I/O system can also be used to perform file I/O -- to write to and read from files. The header fstream must be used to input or output files.

Opening and Closing Files

To open a file, you must link the file to a stream. The three stream types are input, output, and input/output. To link these streams to a file, the stream must be declared to be of class ifstream, ofstream or fstream for input, output, or input/output respectively. The following code declares three streams, one of each type:

ifstream input_stream;
ofstream output_stream;
fstream io_stream;

To open and output a file named sampfile during initialization, the following would be used:

ofstream output_stream("sampfile");

or

ofstream output_stream;
output_stream.open("sampfile");

The ifstream, ofstream, and fstream classes have constructor functions that automatically open a file once it is linked to a stream. To close the file above, you would use the following code:

output_stream.close();

These classes require no parameters in their declarations, and their close() functions will return no value.

Reading and Writing Text Files

An easy way to read from and write to a text file is by using the << and >> operators. We will now look at two sample programs. The first program writes to a file and the second example reads from that same file.

#include 
#include 
using namespace std;
int main()
{
    ofstream opstream("sampfile");
    if(!opstream) {
        cout << "File cannot be opened.\n";
        return 1;
    }
    opstream << 3.1415 << " " << 23 << '\n' << "Test stream.";
    opstream.close();
    return 0;
}

Now that we have written to sampfile, let's read from it:

#include 
#include 
using namespace std;
int main()
{
    int i;
    float f;
    char ch;
    char str[25];
    ifstream ipstream("sampfile");
    if(!ipstream) {
        cout << "File cannot be opened.";
        return 1;
    }
    ipstream >> f;
    ipstream >> i;
    ipstream >> ch;
    ipstream >> str;
    cout << i << " " << f << " " << ch << " " << str;
    ipstream.close();
    return 0;
}

Your output should be:

3.1415 23
Test stream.

C++ has smart operators. If you had read the variables from the file in a slightly different order:

ipstream >> i;
ipstream >> f;
ipstream >> ch;
ipstream >> str;

the output would have been:

3 0.1415 2 3

C++ will do whatever it can to read the types that you have specified. If it can't find anything to fill the variable, it will error.

Other I/O Considerations

We will now explore member functions and other topics relating to I/O.

EOF

The member function eof() is used to determine when the eofbit has been set, which means that an input stream has reached the end of a file. The following program will display on the screen the contents of the file sampfile:

#include 
#include 
using namespace std;
int main()
{
    char ch;
    ifstream ipstream("sampfile", ios::in | ios::binary);
    if(!ipstream) {
        cout << "File cannot be opened.";
        return 1;
    }
    while(!ipstream.eof()) {
        ipstream.get(ch);
        // check for eof()
        if(!ipstream.eof()) cout << ch;
    }
    ipstream.close();
    return 0;
}

The while condition in this example reads "while we have not reached the end of the file ipstream." Your output will be every character in that file.

Another function that works in the same manner is fail(). It will not only stop reading at the end of the file, but if the file fails for any other reason.

    Note: This program will read sampfile as unformatted binary. Unformatted binary and binary I/O functions are addressed in great detail in your textbook.

Random Access

Many times, you do not want to read and write data to a file sequentially. Applications that store data to disk, like databases or spreadsheets, need to be able to read and write from anywhere in the file so that data can be updated and queried. We call this functionality "random access."

There are two functions that allow for random, rather than sequential, access to a file. These functions are seekg() and seekp(). The seekg() function moves the get pointer of the referenced file, while seekp() moves the put pointer of a file. These functions take an integer argument and move the read or write pointer to that record location in a file -- it is not a byte location. If the records in the file are larger, the argument acts as a multiplier.

    Note: If you read to the end of a file, a failbit will be set and you will not be able to search again until it is cleared.

Checking I/O Status

The ios class defines a type, iostate, which is an enumeration. This enumeration includes members that relate to the status of an I/O stream.
Name Meaning
ios::goodbit No error bits set
ios::eofbit 1 when end-of-file is encountered; 0 otherwise
ios::failbit 1 when a (possibly) nonfatal I/O error has occurred; 0 otherwise
ios::badbit 1 when a fatal I/O error has occurred; 0 otherwise

Table 12-4: iostate Members Table.

To check the current status of a stream, you can use the rdstate() function. This function is also a member of the class ios:

iostate rdstate();

The above code will return one of the values from the table. If there are no problems, goodbit will be returned. Otherwise, one of the problem members of the enumeration will be returned.

Using C++'s input and output system can be very easy and powerful. However there are some things you need to be aware of, such as what input functions may throw and exception or set error flags. You should consult your compiler's reference as well as the textbook on these matters.

Array-Based I/O

In addition to console and file I/O, C++ allows for I/O to and from arrays using streams. A character array can serve as the input device, output device, or both. Everything that applies to regular C++ I/O streams also applies to array-based I/O. The only difference is that an array of characters, rather than an object, is linked to the stream. In order to use array-based I/O, the header must be included in your program.

    Note: Array-based input and output has been deprecated by the latest standards. While it is still applicable its days are numbered. String-based streams are available for future use and are explained as well.

Array-Based Classes

The following are the array-based I/O classes used to create input, output, and input/output streams respectively: istrstream, ostrstream, strstream. These classes are derived from the classes in ios and have access to any of the similar class ( istream, ostream ) ios member functions.

Creating an Array-Based Output Stream

Based on our previous studies of arrays and I/O, you should be able to follow the following sample program.

#include 
#include 
using namespace std;
int main()
{
    char str[50];
    ostrstream outa(str, sizeof(str));
    outa << "This is a test. ";
    outa << 623;
    outa << 'A' << ' ' << 3.1415 << ends;
    cout << str;
    return 0;
}

The output will look like this:

This is a test. 623A 3.1415

Creating an Array-Based Input Stream

Let's look at our modified sample program:

#include 
#include 
using namespace std;
int main()
{
    char a[] = "Testing 1 2.3";
    istrstream ins(a);
    int j;
    char str[50];
    float f;
    ins >> str;
    ins >> j;
    ins >> f;
    cout << f << " " << j << " " << str;
    return 0;
}

The output looks like this:

2.3 1 Testing

String-Based I/O

In addition to the array-based I/O, C++ allows for I/O to and from strings using streams. A string is a C++ type that is described in detail in the C++ Primer Plus book. This string type can serve as the input device, output device, or both. In order to use character- based I/O, the header must be included in your program.

String-Based Stream Classes

The following are the string-based I/O classes used to create input, output, and input/output streams respectively istringstream, ostringstream, stringstream. These classes are derived from the classes in ios and have access to any of the similar class ( istream, ostream )member functions.

Creating an String-Based Output Stream

Compare these to the deprecated array-based classes.

#include 
#include 
using namespace std;
int main()
{
    ostringstream outa;
    outa << "This is a test. ";
    outa << 623;
    outa << 'A' << ' ' << 3.1415 << ends;
    cout << outa.str();
    return 0;
}

The output will look like this:

This is a test. 623A 3.1415

Creating a String-Based Input Stream

Let's look at our modified input sample program:

#include 
#include 
using namespace std;
int main()
{
    istringstream ins("Testing 1 2.3");
    int j;
    char str[50];
    float f;
    ins >> str;
    ins >> j;
    ins >> f;
    cout << f << " " << j << " " << str;
    return 0;
}

The output looks like this:

2.3 1 Testing

Linkage

You will learn a bit about linkage and separate compilation units in this final section of the course.

Separate Compilation Units

Structured languages (of which C++ is one) use modularized sections of code that are separately compiled and linked to form the program. This allows for reuse, and for thorough testing of a piece of code. It also allows for more than one programmer to work on different areas of a project at the same time.

In previous sections, we've learned about the standard functions that are stored in libraries, and pre-compiled into object code. At link time, the linker phase of your compilation will select pieces of code from the library and add these bits of code to create a machine executable code that is your program.

In C++, good program design demands that you write your source code units separately and that your project manager or command-line linker to form a single executable file link them. Structure your program with one header for each class or set of related functions, and one implementation file for that class or function source code. This header and source file combination will form a translation unit. A translation unit includes your source files and headers, as well as all the files that may have been added to it indirectly through the included headers.

C Linkage

If you mix C and C++ sources in a project, the files with a .cpp extension will be compiled as C++, while those with .c extension will be compiled as C. When it comes time to link these compiled sources, name mangling will cause the code to be unresolved and your program will fail to be built. You may enable your C++ compiler by setting a flag on the command line when you compile, or by setting a preference in your project's settings. You can also use an extern C statement in your source files to tell the compiler you did not use name mangling for those specific functions.

extern "C" {
// function prototypes here
}

When the compiler sees those functions in your C++ source code, it knows not to look for name-mangled object code.

The Macintosh "Universal Headers" are wrapped in the extern C declaration, so it is safe to use them in a C++ program without fear of name mangling problems.

Copyright © 1998-2007, Games++ All rights reserved. | Privacy Policy