CONTENTS
Section 8.1 An Object-Oriented Library 284
Section 8.2 Condition States 287
Section 8.3 Managing the Output Buffer 290
Section 8.4 File Input and Output 293
Section 8.5 String Streams 299
In C++, input/output is provided through the library. The library defines a family of types that support IO to and from devices such as files and console windows. Additional types allow string
s to act like files, which gives us a way to convert data to and from character forms without also doing IO. Each of these IO types defines how to read and write values of the built-in data types. In addition, class designers generally use the library IO facilities to read and write objects of the classes that they define. Class types are usually read and written using the same operators and conventions that the IO library defines for the built-in types.
This chapter introduces the fundamentals of the IO library. Later chapters will cover additional capabilities: Chapter 14 will look at how we can write our own input and output operators; Appendix A will cover ways to control formatting and random access to files.
Our programs have already used many IO library facilities:
• istream
(input stream) type, which supports input operations
• ostream
(output stream) type, which provides output operations
• cin
(pronounced see-in) an istream
object that reads the standard input.
• cout
(pronounced see-out) an ostream
object that writes to the standard output
• cerr
(pronounced see-err) an ostream
object that writes to the standard error. cerr
is usually used for program error messages.
• operator >>
, which is used to read input from an istream
object
• operator <<
, which is used to write output to an ostream
object
• getline
function, which takes a reference to an istream
and a reference to a string
and reads a word from the istream
into the string
This chapter looks briefly at some additional IO operations, and discusses support for reading and writing files and string
s. Appendix A covers how to control formatting of IO operations, support for random access to files, and support for unformatted IO. This primer does not describe the entire iostream
library—in particular, we do not cover the system-specific implementation details, nor do we discuss the mechanisms by which the library manages input and output buffers or how we might write our own buffer classes. These topics are beyond the scope of this book. Instead, we’ll focus on those portions of the IO library that are most useful in ordinary programs.
The IO types and objects we’ve used so far read and write streams of data and are used to interact with a user’s console window. Of course, real programs cannot be limited to doing IO solely to or from a console window. Programs often need to read or write named files. Moreover, it can be quite convenient to use the IO operations to format data in memory, thereby avoiding the complexity and run-time expense of reading or writing to a disk or other device. Applications also may have to read and write languages that require wide-character support.
Conceptually, neither the kind of device nor the character size affect the IO operations we want to perform. For example, we’d like to use >>
to read data regardless of whether we’re reading a console window, a disk file, or an in-memory string. Similarly, we’d like to use that operator regardless of whether the characters we read fit in a char
or require the wchar_t
(Section 2.1.1, p. 34) type.
At first glance, the complexities involved in supporting or using these different kinds of devices and different sized character streams might seem a daunting problem. To manage the complexity, the library uses inheritance to define a set of object-oriented classes. We’ll have more to say about inheritance and object-oriented programming in Part IV, but generally speaking, types related by inheritance share a common interface. When one class inherits from another, we (usually) can use the same operations on both classes. More specifically, when two types are related by inheritance, we say that one class “inherits” the behavior—the interface—of its parent. In C++ we speak of the parent as the base class and the inheriting class as a derived class.
The IO types are defined in three separate headers: iostream
defines the types used to read and write to a console window, fstream
defines the types used to read and write named files, and sstream
defines the types used to read and write in-memory string
s. Each of the types in fstream
and sstream
is derived from a corresponding type defined in the iostream
header. Table 8.1 lists the IO classes and Figure 8.1 on the next page illustrates the inheritance relationships among these types. Inheritance is usually illustrated similarly to how a family tree is displayed. The topmost circle represents a base (or parent) class. Lines connect a base class to its derived (or children) class(es). So, for example, this figure indicates that istream
is the base class of ifstream
and istringstream
. It is also the base class for iostream
, which in turn is the base class for sstream
and fstream
classes.
Table 8.1. IO Library Types and Headers
Figure 8.1. Simplified iostream
Inheritance Hierarchy
Because the types ifstream
and istringstream
inherit from istream
, we already know a great deal about how to use these types. Each program we’ve written that read an istream
could be used to read a file (using the ifstream
type) or a string
(using the istringstream
type). Similarly, programs that did output could use an ofstream
or ostringstream
instead of ostream
. In addition to the istream
and ostream
types, the iostream
header also defines the iostream
type. Although our programs have not used this type, we actually know a good bit about how to use an iostream
. The iostream
type is derived from both istream
and ostream
. Being derived from both types means that an iostream
object shares the interface of both its parent types. That is, we can use an iostream
type to do both input and output to the same stream. The library also defines two types that inherit from iostream
. These types can be used to read or write to a file or a string
.
Using inheritance for the IO types has another important implication: As we’ll see in Chapter 15, when we have a function that takes a reference to a base-class type, we can pass an object of a derived type to that function. This fact means that a function written to operate on istream&
can be called with an ifstream
or istringstream
object. Similarly, a function that takes an ostream&
can be called with an ofstream
or ostringstream
object. Because the IO types are related by inheritance, we can write one function and apply it to all three kinds of streams: console, disk files, or string streams.
The stream classes described thus far read and write streams composed of type char
. The library defines a corresponding set of types supporting the wchar_t
type. Each class is distinguished from its char
counterpart by a “w
” prefix. Thus, the types wostream, wistream
, and wiostream
read and write wchar_t
data to or from a console window. The file input and output classes are wifstream, wofstream
, and wfstream
. The wchar_t
versions of string
stream input and output are wistringstream, wostringstream
, and wstringstream
. The library also defines objects to read and write wide characters from the standard input and standard output. These objects are distinguished from the char
counterparts by a “w
” prefix: The wchar_t
standard input object is named wcin;
standard output is wcout
; and standard error is wcerr
.
Each of the IO headers defines both the char
and wchar_t
classes and standard input/output objects. The stream-based wchar_t
classes and objects are defined in iostream
, the wide character file stream types in fstream
, and the wide character stringstream
s in sstream
.
For reasons that will be more apparent when we study classes and inheritance in Parts III and IV, the library types do not allow allow copy or assignment:
This requirement has two particularly important implications. As we’ll see in Chapter 9, only element types that support copy can be stored in vector
s or other container types. Because we cannot copy stream objects, we cannot have a vector
(or other container) that holds stream objects.
The second implication is that we cannot have a parameter or return type that is one of the stream types. If we need to pass or return an IO object, it must be passed or returned as a pointer or reference:
Typically, we pass a stream as a nonconst
reference because we pass an IO object intending to read from it or write to it. Reading or writing an IO object changes its state, so the reference must be nonconst
.
Before we explore the types defined in fstream
and sstream
, we need to understand a bit more about how the IO library manages its buffers and the state of a stream. Keep in mind that the material we cover in this section and the next applies equally to plain streams, file streams, or string
streams.
Inherent in doing IO is the fact that errors can occur. Some errors are recoverable; others occur deep within the system and are beyond the scope of a program to correct. The IO library manages a set of condition state members that indicate whether a given IO object is in a usable state or has encountered a particular kind of error. The library also defines a set of functions and flags, listed in Table 8.2, that give us access to and let us manipulate the state of each stream.
Table 8.2. IO Library Condition State
As an example of an IO error, consider the following code:
int ival;
cin >> ival;
If we enter Borges
on the standard input, then cin
will be put in an error state following the unsuccessful attempt to read a string of characters as an int
. Similarly, cin
will be in an error state if we enter an end-of-file. Had we entered 1024, then the read would be successful and cin
would be in a good, non-error state.
To be used for input or output, a stream must be in a non-error state. The easiest way to test whether a stream is okay is to test its truth value:
The if
directly tests the state of the stream. The while
does so indirectly by testing the stream returned from the expression in the condition. If that input operation succeeds, then the condition tests true
.
Many programs need only know whether a stream is valid. Other programs need more fine-grained access to and control of the state of the stream. Rather than knowing that the stream is in an error state, we might want to know what kind of error was encountered. For example, we might want to distinguish between reaching end-of-file and encountering an error on the IO device.
Each stream object contains a condition state member that is managed through the setstate
and clear
operations. This state member has type iostate
, which is a machine-dependent integral type defined by each iostream
class. It is used as a collection of bits, much the way we used the int_quiz1
variable to represent test scores in the example in Section 5.3.1 (p. 156).
Each IO class also defines three const
values of type iostate
that represent particular bit patterns. These const
values are used to indicate particular kinds of IO conditions. They can be used with the bitwise operators (Section 5.3, p. 154) to test or set multiple flags in one operation.
The badbit
indicates a system level failure, such as an unrecoverable read or write error. It is usually not possible to continue using a stream after such an error. The failbit
is set after a recoverable error, such as reading a character when numeric data was expected. It is often possible to correct the problem that caused the failbit
to be set. The eofbit
is set when an end-of-file is encountered. Hitting end-of-file also sets the failbit
.
The state of the stream is revealed by the bad, fail, eof
, and good
operations. If any of bad, fail
, or eof
are true
, then testing the stream itself will indicate that the stream is in an error state. Similarly, the good
operation returns true
if none of the other conditions is true
.
The clear
and setstate
operations change the state of the condition member. The clear
operations put the condition back in its valid state. They are called after we have remedied whatever problem occurred and we want to reset the stream to its valid state. The setstate
operation turns on the specified condition to indicate that a problem occurred. setstate
leaves the existing state variables unchanged except that it adds the additional indicated state(s).
We might manage an input operation as follows:
This loop reads cin
until end-of-file or an unrecoverable read error occurs. The condition uses a comma operator (Section 5.9, p. 168). Recall that the comma operator executes by evaluating each operand and returns its rightmost operand as its result. The condition, therefore, reads cin
and ignores its result. The result of the condition is the result of !cin.eof()
. If cin
hit end-of-file, the condition is false and we fall out of the loop. If cin
did not hit end-of-file, we enter the loop, regardless of any other error the read might have encountered.
Inside the loop, we first check whether the stream is corrupted. If so, we exit by throwing an exception (Section 6.13, p. 215). If the input was invalid, we print a warning, and clear the failbit
state. In this case, we execute a continue
(Section 6.11, p. 214) to return to the start of the while
to read another value into ival
. If there were no errors, the rest of the loop can safely use ival
.
The rdstate
member function returns an iostate
value that corresponds to the entire current condition state of the stream:
Often we need to set or clear multiple state bits. We could do so by making multiple calls to the setstate
or clear
functions. Alternatively, we could use the bitwise OR (Section 5.3, p. 154) operator to generate a value to pass two or more state bits in a single call. The bitwise OR generates an integral value using the bit patterns of its operands. For each bit in the result, the bit is 1 if the corresponding bit is 1 in either of its operands. For example:
// sets both the badbit and the failbit
is.setstate(ifstream::badbit | ifstream::failbit);
tells the object is
to turn on both the failbit
and the badbit
. The argument
is.badbit | is.failbit
creates a value in which the bits corresponding to the badbit
and to the failbit
are both turned on—that is they are both set to 1. All other bits in the value are zero. The call to setstate
uses this value to turn on the bits corresponding to badbit
and failbit
in the stream’s condition state member.
Each IO object manages a buffer, which is used to hold the data that the program reads and writes. When we write
os << "please enter a value: ";
the literal string is stored in the buffer associated with the stream os
. There are several conditions that cause the buffer to be flushed—that is, written—to the actual output device or file:
return
from main
.endl
.unitbuf
manipulator to set the stream’s internal state to empty the buffer after each output operation.tie
the output stream to an input stream, in which case the output buffer is flushed whenever the associated input stream is read.Our programs have already used the endl
manipulator, which writes a newline and flushes the buffer. There are two other similar manipulators. The first, flush
, is used quite frequently. It flushes the stream but adds no characters to the output. The second, ends
, is used much less often. It inserts a null character into the buffer and then flushes it:
unitbuf
ManipulatorIf we want to flush every output, it is better to use the unitbuf
manipulator. This manipulator flushes the stream after every write:
cout << unitbuf << "first" << " second" << nounitbuf;
is equivalent to writing
cout << "first" << flush << " second" << flush;
The nounitbuf
manipulator restores the stream to use normal, system-managed buffer flushing.
When an input stream is tied to an output stream, any attempt to read the input stream will first flush the buffer associated output stream. The library ties cout
to cin
, so the statement
cin >> ival;
causes the buffer associated with cout
to be flushed.
Interactive systems usually should be sure that their input and output streams are tied. Doing so means that we are guaranteed that any output, which might include prompts to the user, has been written before attempting to read.
The tie
function can be called on either istream
or an ostream
. It takes a pointer to an ostream
and ties the argument stream to the object on which tie
was called. When a stream ties itself to an ostream
, then any IO operation on the stream that called tie
flushes the buffer associated with the argument it passed to tie
.
An ostream
object can be tied to only one istream
object at a time. To break an existing tie, we pass in an argument of 0.
The fstream
header defines three types to support file IO:
ifstream
, derived from istream
, reads from a file.ofstream
, derived from ostream
, writes to a file.fstream
, derived from iostream
, reads and writes the same file.The fact that these types are derived from the corresponding iostream
types means that we already know most of what we need to know about how to use the fstream
types. In particular, we can use the IO operators (<<
and >>
) to do formatted IO on a file, and the material covered in the previous sections on condition states apply identically to fstream
objects.
In addition to the behavior that fstream
types inherit, they also define two new operations of their own—open
and close
—along with a constructor that takes the name of a file to open. These operations can be called on objects of fstream, ifstream
, or ofstream
but not on the other IO types.
So far our programs have used the library-defined objects, cin, cout
, and cerr
. When we want to read or write a file, we must define our own objects, and bind them to the desired files. Assuming that ifile
and ofile
are strings
with the names of the files we want to read and write, we might write code such as
// construct an ifstream and bind it to the file named ifile
ifstream infile(ifile.c_str());
// ofstream output file object to write file named ofile
ofstream outfile(ofile.c_str());
to define and open a pair of fstream
objects. infile
is a stream that we can read and outfile
is a stream that we can write. Supplying a file name as an initializer to an ifstream
or ofstream
object has the effect of opening the specified file.
These definitions define infile
as a stream object that will read from a file and outfile
as an object that we can use to write to a file. Neither object is as yet bound to a file. Before we use an fstream
object, we must also bind it to a file to read or write:
We bind an existing fstream
object to the specified file by calling the open
member. The open
function does whatever system-specific operations are required to locate the given file and open it for reading or writing as appropriate.
After opening a file, it is usually a good idea to verify that the open succeeded:
This condition is similar to those we’ve used to test whether cin
had hit end-of-file or encountered some other error. When we test a stream, the effect is to test whether the object is “okay” for input or output. If the open
fails, then the state of the fstream
object is that it is not ready for doing IO. When we test the object
if (outfile) // ok to use outfile?
a true
return means that it is okay to use the file. Because we want to know if the file is not okay, we invert the return from checking the stream:
if (!outfile) // not ok to use outfile?
Once an fstream
has been opened, it remains associated with the specified file. To associate the fstream
with a different file, we must first close
the existing file and then open
a different file:
It is essential that we close
a file stream before attempting to open a new file. The open
function checks whether the stream is already open. If it is open, then it sets its internal state to indicate that a failure has happened. Subsequent attempts to use the file stream will fail.
Consider a program that has a vector
containing names of files it should open and read, doing some processing on the words stored in each file. Assuming the vector
is named files
, such a progam might have a loop like the following:
Each trip through the loop constructs the ifstream
named input
open to read the indicated file. The initializer in the constructor uses the arrow operator (Section 5.6, p. 164) which dereferences it
and fetches the c_str
member from the underlying string
that it
currently denotes. The file is opened by the constructor, and assuming the open
succeeded, we read that file until we hit end-of-file or some other error condition. At that point, input
is in an error state. Any further attempt to read from input
will fail. Because input
is local to the while
loop, it is created on each iteration. That means that it starts out each iteration in a clean state—input.good()
is true
.
If we wanted to avoid creating a new stream object on each trip through the while
, we might move the definition of input
out of the while
. This simple change means that we must manage the stream state more carefully. When we encounter end-of-file, or any other error, the internal state of the stream is set so that further reads or writes are not allowed. Closing a stream does not change the internal state of the stream object. If the last read or write operation failed, the state of the object remains in a failure mode until we execute clear
to reset the condition of the stream. After the clear
, it is as if we had created the object afresh.
If we wish to reuse an existing stream object, our while
loop must remember to close
and clear
the stream on each trip through the loop:
Had we neglected the call to clear
, this loop would read only the first file. To see why, consider what happens in this loop: First we open the indicated file. Assuming open
succeeded, we read the file until we hit end-of-file or some other error condition. At that point, input
is in an error state. If we close
but do not clear
the stream, then any subsequent input operation on input
will fail. Once we have close
d the file, we can open
the next one. However, the read of input
in the inner while
will fail—after all, the last read from this stream hit end-of-file. The fact that the end-of-file was on a different file is irrelevant!
If we reuse a file stream to read or write more than one file, we must clear
the stream before using it to read from another file.
Whenever we open a file—either through a call to open
or as part of initializing a stream from a file name—a file mode is specified. Each fstream
class defines a set of values that represent different modes in which the stream could be opened. Like the condition state flags, the file modes are integral constants that we use with the bitwise operators (Section 5.3, p. 154) to set one or more modes when we open a given file. The file stream constructors and open
have a default argument (Section 7.4.1, p. 253) to set the file mode. The value of the default varies based on the type of the stream. Alternatively, we can supply the mode in which to open the file. Table 8.3 on the next page lists the file modes and their meanings.
Table 8.3. File Modes
The modes out, trunc
, and app
may be specifed only for files associated with an ofstream
or an fstream
; in
may be specified only for files associated with either ifstream
or fstream
. Any file may be opened in ate
or binary
mode. The ate
mode has an effect only at the open: Opening a file in ate
mode puts the file at the end-of-file immediately after the open. A stream opened in binary
mode processes the file as a sequence of bytes; it does no interpretation of the characters in the stream.
By default, files associated with an ifstream
are opened in in
mode, which is the mode that permits the file to be read. Files opened by an ofstream
are opened in out
mode, which permits the file to be written. A file opened in out
mode is truncated: All data stored in the file is discarded.
The only way to preserve the existing data in a file opened by an ofstream
is to specify app
mode explicitly:
// output mode by default; truncates file named "file1"
ofstream outfile("file1");
// equivalent effect: "file1" is explicitly truncated
ofstream outfile2("file1", ofstream::out | ofstream::trunc);
// append mode; adds new data at end of existing file named "file2"
ofstream appfile("file2", ofstream::app);
The definition of outfile2
uses the bitwise OR operator (Section 5.3, p. 154) to open inOut
in both out
and trunc
mode.
An fstream
object can both read and write its associated file. How an fstream
uses its file depends on the mode specified when we open the file.
By default, an fstream
is opened with both in
and out
set. A file opened with both in
and out
mode set is not truncated. If we open the file associated with an fstream
with out
mode, but not in
mode specified, then the file is truncated. The file is also truncated if trunc
is specified, regardless of whether in
is specified. The following definition opens the file copyOut
in both input and output mode:
// open for input and output
fstream inOut("copyOut", fstream::in | fstream::out);
Appendix A.3.8 (p. 837) discusses how to use a file that is opened for both input and output.
The mode is set each time a file is opened:
The first call to open
specifies ofstream::out
. The file named “scratchpad” in the current directory is opened in output mode; the file will be truncated. When we open the file named “precious,” we ask for append mode. Any data in the file remains, and all writes are done at the end of the file. When we opened “out,” we did not specify an output mode explicitly. It is opened in out
mode, meaning that any data currently in “out” is discarded.
Any time open
is called, the file mode is set, either explicitly or implicitly. If a mode is not specified, the default value is used.
Not all open modes can be specified at once. Some are nonsensical, such as opening a file setting both in
and trunc
. That would yield a stream we intend to read but that we have truncated so that there is no data to read. Table 8.4 lists the valid mode combinations and their meanings.
Table 8.4. File Mode Combinations
Any open mode combination may also include ate
. The effect of adding ate
to any of these modes changes only the initial position of the file. Adding ate
to any of these mode combinations positions the file to the end before the first input or output operation is performed.
Several programs in this book open a given file for input. Because we need to do this work in several programs, we’ll write a function, named open_file
, to perform it. Our function takes references to an ifstream
and a string
. The string
holds the name of a file to associate with the given ifstream
:
Because we do not know what state the stream is in, we start by calling close
and clear
to put the stream into a valid state. We next attempt to open
the given file. If the open fails, the stream’s condition state will indicate that the stream is unusable. We finish by returning the stream, which is either bound to the given file and ready to use or is in an error condition.
The iostream
library supports in-memory input/output, in which a stream is attached to a string
within the program’s memory. That string
can be written to and read from using the iostream
input and output operators. The library defines three kinds of string streams:
• istringstream
, derived from istream
, reads from a string
.
• ostringstream
, derived from ostream
, writes to a string
.
• stringstream
, derived from iostream
, reads and writes a string
.
To use any of these classes, we must include the sstream
header.
Like the fstream
types, these types are derived from the iostream
types, meaning that all the operations on iostream
s also apply to the types in sstream
. In addition to the operations that the sstream
types inherit, these types have a constructor that takes a string
. The constructor copies the string
argument into the stringstream
object. The operations that read and write the stringstream
read or write the string
in the object. These classes also define a member named str
to fetch or set the string
value that the stringstream
manipulates.
Note that although fstream
and sstream
share a common base class, they have no other interrelationship. In particular, we cannot use open
and close
on a stringstream
, nor can we use str
on an fstream
.
Table 8.5. stringstream
-Specific Operations
stringstream
We’ve seen programs that need to deal with their input a word at a time or a line at a time. The first sort of programs use the string
input operator and the second use the getline
function. However, some programs need to do both: They have some processing to do on a per-line basis and other work that needs to be done on each word within each line. Using stringstreams
lets us do so:
Here we use getline
to get an entire line from the input. To get the words in each line, we bind an istringstream
to the line that we read. We can then use the normal string
input operator to read the words from each line.
stringstream
s Provide Conversions and/or FormattingOne common use of stringstream
s is when we want to obtain automatic formatting across multiple data types. For example, we might have a collection of numeric values but want their string
representation or vice versa. The sstream
input and output operations automatically convert an arithmetic type into its corresponding string
representation or back again:
Here we create an empty ostringstream
object named format_message
and insert the indicated text into that object. What’s important is that the int
values are automatically converted to their printable string
equivalents. The contents of format_message
are the characters
val1: 512 val2: 1024
We could retrieve the numeric value by using an istringstream
to read from the string
. Reading an istringstream
automatically converts from the character representation of a numeric value to its corresponding arithmetic value:
Here we use the str
member to obtain a copy of the string
associated with the ostringstream
we previously created. We bind input_istring
to that string
. When we read input_istring
, the values are converted back to their original numeric representations.
To read input_string
, we must parse the string
into its component parts. We want the numeric values; to get them we must read (and ignore) the labels that are interspersed with the data we want.
Because the input operator reads typed values, it is essential that the types of the objects into which we read be compatible with the types of the values read from the stringstream
. In this case, input_istring
had four components: The string
value val1:
followed by 512
followed by the string val2:
followed by 1024
. As usual, whenweread strings
using the input operator, whitespace is ignored. Thus, when we read the string
associated with format_message
, we can ignore the newlines that are part of that value.
C++ uses library classes to handle input and output:
• The iostream
classes handle stream-oriented input and output
• The fstream
classes handle IO to named files
• The stringstream
classes do IO to in-memory string
s
All of these classes are related by inheritance. The input classes inherit from istream
and the output classes from ostream
. Thus, operations that can be performed on an istream
object can also be performed on either an ifstream
or an istringstream
. Similarly for the output classes, which inherit from ostream
.
Each IO object maintains a set of condition states that indicate whether IO can be done through this object. If an error is encountered—such as hitting end-of-file on an input stream—then the object’s state will be such that no further input can be done until the error is rectified. The library provides a set of functions to set and test these states.
A class that is the parent of another class. The base class defines the interface that a derived class inherits.
Flags and associated functions usable by any of the stream classes that indicate whether a given stream is usable. States and functions to get and set these states are listed in Table 8.2 (p. 288).
A derived class is one that shares an interface with its parent class.
Flags defined by the fstream
classes that are specified when opening a file and control how a file can be used. Listed in Table 8.3 (p. 297).
Stream object that reads or writes a named file. In addition to the normal iostream
operations, the fstream
class also defines open
and close
members. The open
member function takes a C-style character string that names the file to open and an optional open mode argument. By default ifstream
s are opened with in
mode, ofstream
s with out
mode, and fstream
s with in
and out
mode set. The close
member closes the file to which the stream is attached. It must be called before another file can be open
ed.
Types that are related by inheritance share a common interface. A derived class inherits properties from its base class. Chapter 15 covers inheritance.
A set of classes related by inheritance. Generally speaking, the base class of an object-oriented library defines an interface that is shared by the classes derived from that base class. In the IO library, the istream
and ostream
classes serve as base classes for the types defined in the fstream
and sstream
headers. We can use an object of a derived class as if it were an object of the base class. For example, we can use the operations defined for istream
on an ifstream
object.
Stream object that reads or writes a string
. In addition to the normal iostream
operations, it also defines an overloaded member named str
. Calling str
with no arguments returns the string
to which the stringstream
is attached. Calling it with a string
attaches the stringstream
to a copy of that string
.