cin
-- type conversion to bool
cin
object has type istream
.
In fact, it is the only object of that type we've seen up until now. Other
than the >>-operator, we haven't used it like we've used other
types; we never try any other operations.
Oddly enough, objects of type istream
can be cast as type
bool
, which means for example that they can be used in the
test condition of a loop or an if
-statement. But what does
that mean?!?!? Let's look at an example:
int j, k=0;
cin >> j;
while(cin) // type conversion to bool
{
k = k + j;
cin >> j;
}
cout << k << endl;
Now what does this do? Well, if I run this program and enter
1 2 3 4;... it'll print out 10. What it's done is to compute the sum of the numbers entered, stopping at the ';' ... but why?
cin
. In particular,
true
, when cin
is in a good state.
false
, when it's in a failure state.
cin
is in a good state. However, when cin
fails to read in an object of the type you've requested, it goes into a
failure state. Once in that state, it doesn't go back to a good state.
So, in our loop:
int
successfully
with cin >> j
the evaluated expression
"cin
" is of type istream
and is cast to the
bool
value true
, meaning the loop continues.
int
but encounter a ';' instead, meaning that the read fails. So the loop
condition for the next iteration takes cin
and casts it to
the bool
value false
, and the loop terminates.
In fact, in this state any subsequent attempts to read will fail,
too. This is a cool trick.
More often than not, we use the fact that the expression cin
>> j
is an expression that evaluates to cin
(with the side effect of reading into the variable j
), to
write the above more compactly as follows:
while(cin >> j)
as follows:
cin >> j
succeeds ...".
int j, k = 0;
// cin << j evaluates to cin, which then returns its state
while(cin >> j)
{
k = k + j;
}
cout << k << endl;
ifstream
typecin
won't help us. However, we
can create an istream
object that acts just like
cin
except that it gets its character stream from a file
rather than a keyboard. So, let's do the same program as above, but
first let's create a file temp
with the
input for our program.
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
// Create istream object that reads from file temp
ifstream fin("temp"); // note: fin has ifstream type
// Loop and add as long as more int's can be read
int j, k=0;
while(fin >> j) // note: quite similar to the above code except with cin vs. fin
{
k = k + j;
}
// Print out the sum k
cout << k << endl;
return 0;
}
A couple of comments follow.
When I say ifstream fin;
it looks like I'm declaring an
object of type ifstream
(and indeed I am!), and yet I
claimed to be creating an object of type istream
, which is
it? Well ... it's both. As you get into more advanced programming, the
idea of subtypes will be important. For now I'll just say this:
cin
and the fin
we created are both of type
istream
in the same way that "square" and "trapazoid" are
both in the category "quadrilateral" - they are subtypes of the type
quadrilateral.
Now, if you run this, it's only going to successfully open and read from
the file temp
if temp
is in the current
directory, i.e. the directory you were in when you launched the
program.
So what happens when your program doesn't find the file it's looking
for? Well, when you create fin
to read from
temp
, and temp
does not exist, then
fin
is in a state which, when cast as a bool
, is
false. Thus, if we want to improve the program above so that it prints an
error message if the file temp
cannot be found, we would do
For a lot of small programs, you simply want to print an error and exit
your program when you can't find the given file. Otherwise, just
carry-on. We usually do this as shown below. Note that "return
1;
" in main has the effect of exiting the entire program
immediately, and returning a non-zero value is the traditional way of
indicating that there was some kind of error.
ifstream fin("temp");
if (!fin)
{
cout << "File \"temp\" not found!" << endl;
return 1; // exit the program!!
}
int
for
example, and the file ends before istream
object can read an
int
, the istream
object goes into an error state
again - i.e. casting it to a bool
would result in the value
false.
// while fin >> k is succeeds..
// When the file ends, (fin >> k) will fail, so the program will exit the loop
while (fin >> k)
{
sum = sum + k;
}
ifstream
object that is open for
reading to a file. How are input file streams closed? Well, when the
ifstream
object goes out of scope that variable dies,
and this closes the connection to the file. If another
ifstream
object is created to read from the same file, it
starts over at the beginning.
fin
explicitly at any time as follows:
fin.close()
ifstream fin1("in1.txt");
ifstream fin2("in2.txt");
int a1, a2;
while( (fin1 >> a1) && (fin2 >> a2) ) // while reading succeeds..
cout << "file1:" << a1 << ", file2:" << a2 << endl;
The above code will open in1.txt and in2.txt at the same time and read (and
print) an integer from each file.
cin
, writing to a file is not much different
from writing to cout
. First, you need to create an
object of type ostream
like cout
, but
which sends its output to a file. To do this, you declare a
variable of type ofstream
.
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
// Create ostream object that writes to file outfile
ofstream fout("outfile");
// Write 1 through 10 on separate lines
int i;
i = 1;
while(i <= 10)
{
fout << i << endl;
i = i + 1;
}
return 0;
}
You don't really have the issue of checking to see if the file is
found, since you're trying to create a new file. If there is file
of that name already there, it gets obliterated ... oops! A fully
featured program might warn the user of this. Can you think of
how you might check whether the file outfile
already
exists?
name
is a string
object with
the name of the file you'd like to open, then
string name;
cin >> name;
ifstream fin(name);
or
string name;
cin >> name;
ifstream fin;
fin.open(name);
opens an input stream to that file.