>> All right. So, one of primary things I want to get done today is talk
about C++ Input/Output. And we really-- you know,
this is Chapter 11, which seems may be a little late since you'd been using
the input/output systems since probably your first
program when you wrote the "Hello World" program way
back in your first course. The problem is C++ I/O
System is quite complicated. There is a book available
in the professional series of Addison-Wesley that's
about 600 pages long and that book is entitled
the C++ I/O System. So, it's big and complicated list. And you really can't begin to understand
it until you've learned about classes and objects and inheritance,
because it's all-- it's a class hierarchy or a fine work
if you'd like for the I/O system. So, I just want to take the opportunity
today to kind of go over how it works with you and you'll begin to
understand some of the things that may have seemed mysterious before. So, here's slide 1. And notice that this is
talking about a class hierarchy and I've even got the phrase
"simplified" in there. And this is unbelievable, right? So you've got this class ios base,
you've got an ios derived from that. You got istream and ostream
classes derived from ios. You've got multiple inheritance,
iostream inheriting from both istream and ostream. You've got fstream inheriting
from iostream. You've got istream inheriting
from istream, and ofstream inheriting from ostream. So those are the classes
in this framework. And the principle really is that
you define a whole lot of things in the base class that many, if not all
of these, are going to be able to use and therefore you don't have to keep
reinventing the wheel or should, in this case, redefining
the wheel on how I/O works for these more specialized classes. You really never use
a base class up here. I don't think it's an abstract base
class but nevertheless it's not intended to be used at the level at which
you start using these classes here. You can use istream or
ostream or iostream and so on. Now, another thing I want to
point out, we do over and over, but still confuses people, and that
is that these things are operators. In fact, they're overloads of the left
shift and the right shift operators, which are classic operators
inherited from the C language which was developed way back. So, these things are operators
and they're binary operators, so they take two arguments,
on the left, on the right. And the way they both
work is by the way, the type of the left argument is
also the return type in both cases, and for the classic operators
that was an integer. And so you could left shift an integer
by a certain amount and the result was that integer left-shifted, or
you could right shift an integer by a certain amount and that would be
that integer right-shifted that amount. But for operators, you
know, you can overload them but you can't really change certain
things about them and the expectation that the left-hand parameter as
the same type as the return value of the operator is something
you can't change. So, let's just bite the bullet
and talk about ios base. These are in namespace std
and has a class ios base. So in the public part of this
class, you have some methods. You've got a fail method
which returns true or false and in essence is telling you if there's
been a failure somewhere, yes or no. You've got an eof method which returns
true or false, telling you if you're at the end of a stream input. You've got binding methods where you
can tie an ostream to specified-- you can tie a current stream
to a specified ostream, and typically that's used to make
relationships between input and output. So for example, when you run a C++ or
run a new output or prompts to the user, and then you read what the user
inputs, well, you want to make sure that the user sees that prompt
before you try to read the input. And tying those two streams together
is what guarantees that to happen. Otherwise, I might operate on
independent time scales and, you know, you might-- the system might somehow
decide to wait an output prompt later when it's more convenient
for lock waiting system and you obviously don't
want that to happen. So that's what tying is for. You got setf which sets format flags. You've got a width function
which is used to set the width but also tell you what the
current width argument is. You've got a fill which is
used to set the fill character but also tell you what
current fill character is. And then you've got some enumerated
types and these are typically bitmasks. So you've got the iostate, the format
flags, openmode, and the seekdirection. Iostate represents good or kind of OK,
eof, end of file state, bad and fail. There's 15 format flags such as
left, showpoint, hex and so on. There are six file openmodes
such in, out, and binary. There are three seekdirections,
seek from the beginning of a file, seek from end, obviously
going backwards in the file, and seek from the current
location in the file. And this is overloaded right now. We're going to talk about
all of these in more detail. So, you've got an unsigned
long state and that's where these iostates are stored. You've got an unsigned long flags, that's where the format
flags are stored. You've got an unsigned long mode and
that's where the modes are stored. You've got a widthvalue, a
precisionvalue, a fillcharacter, and finally this mysterious
thing called a streambuffer, and that is actually the-- notice
that's a pointer to a streambuff and that is how one of
these objects knows which stream is supposed
to be operating on. And streams are yet another
layer of mystery that are-- you have to define in terms of the
operating system and we're going to not talk about those in this class. We'll talk about those a little bit when
you take the course, operating systems. OK. So that's an introductory
look at the ios base class. So all of these things, the state, the
formatflags, openmodes, seekdirections, file and these various
top level functions, notice that I've got some little
dots in there, indicating to you that I haven't given you
all of the functions. But these are all in the
ios base class which means that whenever you get unto the
level of Cout, for example, you inherited all of these stuff. So, here is a more detailed look
this onto the ios base methods. You've got good, end of file, fail, bad. You got null operator and you
got a clear, and a setstate. You probably won't use all of these
but we do use fail quite often. We use clear quite often. And there's this enumeration tie. These are the iostates, and the
reason I'm going through this here is to show you how it might be implemented. The C++ specification
dictate how it's implemented, but this is the model that's assumed. It's kind of the proof the next possible
model and a lot of implementations in C++ doing thing--
use this kind of thing. So, in this model, the
good bit is the zero state. If you have the zero state,
you say everything is OK. It's not really a bit, but zero. So, end of file bit will be
the first bit in that byte. The fail bit will be the
second bit in that byte, and the bad bit will be
the third bit in that byte. Third bit corresponding
to the number four. And these are stored in this
unsigned long called state, and that's where they can be read. So, the ios base has formatting methods. So, you can-- there's one called flags and that returns to current
format flags. There's a non-const version of
flags which takes an argument. And if you put that argument
in, it sets the format flags to be whatever those newflags are. Returns the oldflag value so that you
can always go back to the state you were in before by calling set all flags. There's a setf which sets--
you can set certain bits, certain bits in those formats. So, it would set the bits that you send
in, leave the rest of the bits unchanged to however they might have been before. You can set bits passing in the bits you
want to set, and mask out with a mask, any collection or format flags you want
to mask out which would have the effect of setting the bits only if
they're not masked by that mask. And there's an unset
which goes with set, and of course that does the opposite that it unsets the bits
that you're passing. So, your numerator type here at the
format flagsm now have them all here, skipws is for skip white space,
left, right, internal, dec, oct, hex. You're familiar with those
a little bit already. Showbase, showpoint, showpositive,
scientific, fixed, uppercase, unitbuf, boolalpha, adjustfield,
basefield, and floatfield. These, I'm not going to talk about,
the rest of these you'll got a chance to use in a future assignment. And then, again, protect it. These are always flags that are stored in a single unsigned long value
called flags, if you want to protect-- protect the data from the output. So, let's talk about the
meaning of this format flags. Now-- Did I mention boolapha here? Yeah. There's boolapha, OK. So, I'm talking about-- I'm
in a different order here. So boolapha reads and writes Boolean
values in the alphabetic notation, where you can write true and it
will interpret as Boolean true, you can write false and it will
interpret is Boolean false. The left flag is left-justify output,
the right flag is right-justify output, internal for numerical output is to the
prefix left and then the fill character and then the number to right. The prefix would be something
like OX or hexadecimal. Skipws means skip white space before
extracting the next character, that's a handy one. Dec means interpret numbers as decimal. Hex means interpret numbers
as hexadecimal. And oct means interpret
numbers as octal. It's kind of a shame, we don't
have a binary but we don't. So, notice that dec, oct, and
hex affect both input and output. Some of these others might
affect input and/or output. If it doesn't make sense
to affect input, and they won't if it doesn't make
sense to effect output, they won't. If it does, then they all
have an appropriate meaning for both input and output. OK. Continuing on, these are more
flags, there's a showbase, showpoint, showpositive, forces as you to write
a plus sign, fixed and scientific. So those are for output, for example,
fixed says, "force decimal notation". I said decimal notation. That's-- actually, I should change that
word because it doesn't mean decimal, I meant the point, force the use of the
point instead of scientific notation. And scientific of course is force
scientific notation of floats. And-- [ Pause ] Unitbuf-- I don't really even
know how to pronounce that one, but what it basically means is, "flush
the buffer after each insertion". And finally, there's uppercase, which
means, "use upper case indicators for hex and decimal if needed". Decimal, that would be on its scientific
notation, there's some letters in there, use upper case letters. And finally, there're some
convenience definitions here. So, the adustfield consist
of left flag, the right flag, and the internal flag, all three. Notice that's a bit wise or--
So, that's [inaudible] all three of those bits together in a
single entity called adjustfield. And that might be used as a mask, so
that if you're fiddling with stuff, you want to make sure that the
changes only occur in the adjustfield, like if you're switching back
across a lot from a decimal to hex or something like that. And the floatfield is
scientific and fixed. It might strike you as strange
that those are different flags. So, they're not considered one
or the opposite of the other, but not exactly clear what would happen
if you had both of those same set. I've been meaning to try that along
these years, I haven't done it yet. All right. So, then there's data
methods in ios base. You've got a fail method, a precision
method, there's two versions. The const just returns
what the precision is. A non-const text an argument and
sets the precision for that argument. Width has two versions that returns
the width argument and then sets it. So, int is the width value and
precision value, and then value of char which is the fill character. Notice that fill character is defaulted
to "blank" or initialized to "blank". And the width values and precision
values are initialized here. And these things are
rather complicated, I think. So for example in width, if
it's zero or less, that can be-- that's an integer remember,
not that unsigned [inaudible]. But if zero or less doesn't have any
the effect, if it's bigger than zero, then on output, it sets the minimum
number of characters that are outputted. And on input, it sets the length
of buffer for string extractions. So in other words, it's the way you
set how many characters you're going to read into a C string. For meaning of precision, if N is less
or equal to zero, that's the default. And that means that precision
is determined by the actual numerical values at hand. So you get up to the capabilities of
the machine, you'll get enough precision to give you the exact calculation
or the exact number that's stored. But if N is positive, then if the fixed
bit is set, that determines the number of places displayed after the point. And if you-- if the fixed bit is
not set, it determines the numbers of significant digits
that are displayed. And finally, there's
the binding methods. There's the rdbuf which is how you
bind a stream an ios base object to a particular input or output
stream, or streambuf, rather. And then this tie, that just returns
a pointer to the tied stream. And there's another tie that says, "OK",
I'm going to actually enforce a tie between this object and the one you
gave me a pointer to, right here. [ Pause ] So, I explained here what tie mean for
an ostream being tied to another stream. And the main thing to know is that
by default, cin is tied to cout, and the net effect, that is as I
said before, you don't give a prompt to a user after you try to
read what the user inputs, make sure you give it before. . And finally, there's
sync with standard io, standard io is C I/O,
the C language I/O. Remember, C++ has to be
a super set of C so we-- and C++ can support standard
I/O using C tie input output. And that's what that is
for, sync with standard io. So we have a stream-- a pointer to
the streambuf called streambuffer and a pointer to a tied stream, a
tied ostream called tied ostream. So, fortunately, this time is
typically our default values and so we don't really have to
get into setting these things, which is really good because that
would make it a total pain in the neck to do anything with this I/O system. But it's set up where you got nice
default settings for all these things. And you have huge flexibility if
you need to change stuff around. So finally, this-- I hope
finally, let's see-- yeah. The last thing in ios base to
talk about is the open modes. And we have in, that's extensively
1 bit, out 2 bit, the second bit. At the end, ate, is the third bit, open
file and append mode is the fourth bit, truncate the file if
it exists, that means, when you open it delete its content. And binary, it means
interpret it as a binary. Now, typically, when you open a
file, it opens in truncate mode. So, if you open a file,
it-- for, I'm sorry. When you open a file for writing,
it's typically in truncate mode, and so what was in the
file before gets deleted. It's interesting, you can open a
file for writing in an app mode which would append whatever
you write to that file instead of rewriting a file from scratch. And finally, enum seek
directions, began, current, and end. I talked about that already. Those are enumerated types and
protected, you have unsigned long which where all these gizmos
are still are all in that mode. [ Pause ] So, the meaning of file modes, in,
has the effect of opening text files for reading with an initial
position at beginning of file. Out, if the open mode is out, then the
effect is to truncate the file empty or create the file for write only. And that's, note, the
same as out trunc, right? So the default is open truncation mode. Out, it was or app, append mode means
you're opening the file for output and append modes so that will find
the end character in that file and start writing layer in that file. Now, it's possible to open a file
for both input and output mode. So it allows you to read from
the file and write to the file. Needless to say that
can get you in trouble if you're not careful
with your program lodging. You can also put an in/out trunc which
is not a default, if you open in and out for reading and writing, you don't
truncate the file by default. It really wouldn't make sense, right? Because what would you read
if you truncate the file, but you can open it that
way if you want to. So you can-- and open it in, in
and out mode and truncate mode, and so that starts with [inaudible]
but then you're allowed to write to it and you can read what you wrote
back and forth, et cetera. Now, I keep saying and but you keep
saying bitwise OR, and it's funny how that works because when
you just want to-- remember, you want to have these little
flags, these that represent bits. So the in bit being set, and
the output out bit being set, and the trunc bit being set, is
accomplished by bitwise-ORing, that flag with that flag and that flag. So that-- effectively, that has a
bit, that has a single bit equal to 1 on certain location, that
has a single bit equal to one in a different location ,
that has a single bit equal to one in the third location. When you bitwise OR those, that
gives you a word with all three of those bits set equal to one. And this is just samples of how these
base methods can be implemented, for example the flags, the
const method just returns flags. Or this, the flags that's not const
allows you to pass in some newflags, it's going to remember the
oldflags, set the flags into-- that's a class variable
equal to the newflags. Unfortunately, that-- if we [inaudible]
our styles, it's simply more readable with this flags would have
an underscore and you'd know that that's the class variable. But you just have to
remember that in this case. So the newflags is this argument, you
set a copy of those into the flags. Remember, that's just unsigned
long, just it's just a number. But then when you return the
oldflags, there's a value. And here's how setf would work, you
pass in some bits that you want to set, and you remember the oldflags, you
set those bits, how do you set bits or you bitwise or them into the flags. And then, we return the oldflags in case we'll not go back
to what we have before. So finally, we can talk about a nice
old friend here, the istream class. This inherits publicly
from class ios base. In class istream is where we
overload the input operator for all of the built-in types,
that C++ [inaudible]. That would be char, int, long, unsigned
char, unsigned int, unsigned long, float, double, long double
, pointer of char, and generally some more having
pointers to any of this defined types in particular would be overloaded here. But the one on that point of the char
is particular important because remember that uses pointer to type char, that's
different from any other pointer type and that it represents a Cstring. So the expectation that that will be
a pointer to an array of characters, that is null terminated at some
point by the null character, that expectation is built-in to C++ ios. And here's something, this is
the first use you've seen of why that semicolon is there that
sometimes we forget to put and the compiler gets
terminally confused by that. And that is because you can go ahead
and declare objects right there when you want to and what-- and in the
case of class istream, we do want to. We want to cin to be an
automatically-declared object, that's declared in the header
file for the istream class. So that's where cin comes from. So it is basically an
object that's global to the std namespace whenever
you include this library. Ostream, similarly, we got an overload
of a bunch of output operators, but I guess, we're calling
it O for output. And, you know, it's inheriting the
ios base class so most of the stuff for both the istream and ostream
is defined in that parent class, but the output operators
are overloaded here. I think I forgot to mention
something else, I did. For input, the class
istream, we have a get method, another get method, and
we have a peek method. And those all have to do with
characters in the stream. Get returns the next character in
the stream and also, in a sense, plucks it out of the stream. There's another version of get that
passes the character in by reference. And it has the same effect. I'm not sure why we have two of
those but I guess some people prefer to say get paren CH close paren. And some other people
prefer to say CH equals get. Of course, there'll be a dot going
with that get for the stream object. But nevertheless, we have two
different ways of getting a character. And that, like I said,
returns that character but it also advances the stream pointer
so that characters is [inaudible] lost. It's gone out of the stream. It's plucked out of the stream. And we have this nifty
thing called peek. And what peek does is
look at the next character without pulling it out of the stream. So sometimes, you need to know what that
character is and not disturb the string. And that would be your peek. And I bet you, in fact,
peek is a const method. I didn't write that in here but
peek should be a const method. And again, remember, we declared cin. OK. For the output, we
overload the output operators. We have a put method. Put takes a character and
inserts it into the stream. Remember, this is only
for characters now. So, we're not-- we can't put
an integer into the stream. We can't put a character
into the stream. So, your basic character by character
methods for input and output are put and get-- put, get and peek, get and
peek for input and put for output. And this might come as
a mall surprise for you, there's three pre-declared
output stream objects. Cout, which of course
you all know about, but there's another one called
cerr, and a third one called clog. These will come up again in a few
minutes but cout is buffered output. Cerr is not buffered output. And clog is buffered output. Different streams-- And these are
three different output streams that when you run a program
inside of default window, all three of those streams go to the
standard output and so they appear on your screen in the same place. But the operating system can
[inaudible] those apart and send them in different places for you. So, you can send cout to screen and see
cerr left side to a different screen. And so this cout might be tied
to some display in a window. Cerr might be to a separate
operator screen. And clog, you can send directly to the file that's logging
whatever you want to log. So, there's more about this pre-defined
objects, cin, cout, cerr, and clog. The cin is the only predefined,
globally-defined or [inaudible] defined object for input. You got three for output and these
all are slightly different set up. So, cout and clog are buffered. Cerr is not buffered. Cin is tied to cout. Clog isn't tied to anything. So, there's a cin dot tie
of the address of cout, which would be in the file iostream. And there's a cerr dot
setf ios base unitbuf. And what that does is say, we automatically clear
the buffer immediately. So, the net effect of having
cerr not be buffered means that if you sent something out the error
stream, it will immediately be sent to wherever the output device is, if you're mapping it to
typically the screen. It will go immediately, whereas,
if you do cout, you're giving the-- it's buffered and that gives
the operating system the option of outputting it whenever it's most
convenient for the other things that are going on in the program. Except, you can't wait so long that
the person doesn't see the prompt if something comes in through cin,
then you got to flush [inaudible]. So now, we talk about the ifstream
class, remember we're going down in that [inaudible], and the F is for file
and I is for input in which you have-- And for input files, you
have this notion of open. And so function call, that's a
method of course, called open. And so, you give it a
C strings filename. Never get away from C
strings, unfortunately. And you give it an open mode
and the [inaudible] open data on open mode is ios base
double colon, in for input. And there's a close method as well, which closes the file
previously opened below. [ Pause ] Oftream, output file stream. Again, you have an open
text of C string filename. But this time, the mode is for
output and trunc by default. And you can open it and change the mode
or you can open it with a different mode but that's the default mode. And it has a close. And close will flush the buffer
into that file and check the file or give it back to the
operating system, basically. OK. So, that's a very brief
overview of that class hierarchy. And I want to go back and
just look at it again. So, we talk about ios
base, and that's where all of these enumerated types are
defined, the flags and so forth. And they're stored in numbers that
are private or protected variables in those-- in that base ios. And we talked about istream. And that's where the input operators
get overloaded and where our get and peek methods are defined. We talked about ostream, and that's where the output operators are
overloaded for all the built-in types, and where the put method is--
makes its first appearance. And iostream, of course,
you get both of those. And then for ifstream,
that inherits from istream, and that's where we add the
open and close methods to files for both the istream and ostream. So, we've talked about a lot
of stuff in these classes. Most of it kind of puts in the
base class and just-- I keep-- want to emphasize that all of
these derived classes inherit all of that stuff from ios
base so that you always-- you have all these flags
and everything sitting there if you want to change any of them. And now, I want to get to this last
bullet, the subject of manipulators. [ Pause ] And this-- this is a list of the
manipulators that I think is exhaustive. But I don't know [inaudible]. For sure, this is an exhaustive list. And these are defined
in iostream itself. [ Pause ] Boolalpha and noboolalpha, showbase,
noshowbase, showpoint and noshowpoint, showpositive, noshowpositive,
uppercase, nouppercase, skipwhitespace, noskipwhitespace. I don't know how to pronounce that word. Unitbuf, unitbuf, nounitbuf,
left, right, internal, dec, hex, oct, fixed, scientific, endl. Endl is one that you've probably
gotten used to using a lot and what that does is insert the end of line
character into these out into the stream and then call flush which
flushes the streambuff. There's also an ends if you happen to be
writing to a string instead to a file. Then you would put a null character
in there instead of end of line. And the way these are used, is you've
had some progress and I'm just going to remind you-- let me turn
this to the board here. [ Noise ] [ Pause ] So where you use these manipulators
is for example, if you want their std, cout, and you want to apply,
let say, the hex manipulator. Then you just put it
in there as std hex. And you can just put a
semicolon there if you want to. Or you could keep sending more
stuff throughout with our operator but I just want to point out
that this is an operator. This is his left argument and
this is his right argument. So we're calling-- that
we're making a call to this operator with
those two arguments. And so, this just sort of tells
you how those are implemented. So, I want to-- So, these
manipulators all have this prototype. Yeah, a reference. That return type is reference
for the stream. And that's the name of the manipulator. And that's-- The input is also
a reference to the stream. And so, for example, if you're going
to create a manipulator called beepbeep that would send out to a debate noise,
whatever your computer term will make. Set that backslash A is what that
is and that's actually for alarm. And this is actually hauled
over from even the days of the old west when we use telegraph. The telegraph keyboard was--
would have an alarm button and that would basically send the bell
to the telegraph box to the person at the other end of that wire
somewhere, and that would kind of tell him to pay attention. But in any case, supposed you want to
say I'll send two beeps down the stream, and you want the name of that
manipulator to be beepbeep, like the roadrunner, then
here's why you would do that. You would define that
function, beepbeep. It takes an ostream as an argument. What it does is send two
alarms down that ostream, OK. And then, it returns that change
to ostream as a [inaudible]. So that's how you would define or
implement, I should have used the word, maybe, the beepbeep manipulators,
that's mode of function with that prototype right there. And the way you would
use it is you just-- you use your output stream and then your
operator call, and then your beepbeep. So that is calling the output operator with left argument standard
output, standard cout, rather. And the right argument is beepbeep,
which is our manipulator here. So, that's kind of the
trick to how make this work. And they're really quite convenient because you can insert a manipulator
right into the stream of arguments that are being called for the
output operator instead of having to stop your output and make a
function call with a dot notation and then go back-- going
back to output again. You know, slip all these
manipulators in as if they were going through the output. And then there are some others, manipulators that are
defined in iomanip. These are a bit harder to
understand how they were-- how they're implemented but their
meaning is not that hard to understand. You can setbase and that means
you're going to set the radix for numerical input or output and the
possible values are 8, 10, and 16. B equals 0 means the default
which is decimal on output and the C rules for integers on input. You can set iosflags. You can reset iosflags. You can setfill. You can setprecision. And you can setw. Those are all manipulators. What they have in common is
that they all take an argument. So, the set base access,
base B argument. Setiosflags takes some mask. Setfill takes a character. Setprecision takes a number
and setwidth takes a number. And these are-- They're a little bit
more complicated to define, well, to implement it rather, but I
think their meaning is clear and the usage is the same. You just put the manipulator in as if it
were being sent to output but of course, it's really doing something
entirely differently. So, that's all I have to say about that. And so, let me turn back this.