Output Stream Formatting -- Addendum
Remember to review general output formatting features at this Programming I
notes set here:
However, you should also be sure to note this very important fact:
- The only formatting feature that effects the one next item
sent to the output stream -- is the field width setting
(width() member function and setw() stream
manipulator
- ALL of the other settings (flags, decimal precision, fill
character, etc) are permanent settings affecting all future
outputs, until those settings are changed
Examples:
double x = 123.4567, a = 432.659;
int y = 12;
cout.setf(ios::right); // same as cout << right;
// right-justify now set until further notice
cout << setw(10) << y; // setw, field width 10, ONLY affects y output
cout << setw(20) << x; // setw, field width 20, ONLY affects x
// printout so far is:
// 12 123.4567
cout.precision(2); // set this way for all output, until further notice
cout << fixed; // same
cout << "x = " << x << '\n';
cout << "a = " << a << '\n';
// output from last two lines:
// x = 123.46
// a = 432.66
WHY does this matter?
In your intro course, you only wrote single file programs, so all output
formatting was for something ONLY YOU were using. However, we are now
writing programs involving multiple files and multiple modules. Imagine
the following scenario:
- You write a class module
- Another programmer writes a main program that USES your class
- Your class contains a function that will do some output, with some
specific formatting
- The "main" module (not written by you) does some output of its own,
also with its own specific formatting
- Outputs are being done with the SHARED object,
std::cout
- Note that any changes YOU make in your function (other than field
width) will be permanent for cout, and will affect the
caller back in "main()"...
- UNLESS... you are polite and put the stream settings back the way
you found them when you are done!
How to capture and restore prior output stream settings
There are three very useful member functions of class ostream
that not only allow you to SET format features, but also that allow you
to capture the existing settings:
precision() // for setting decimal precision
fill() // for setting the fill character
flags() // for setting format flags (like fixed, left, right, etc)
Each of these functions has:
- a no-parameter version that returns the current setting
- a 1-parameter version that allows you to pass in a new setting
To capture the current setting, you can call the NO-parameter version of
each. Make sure to use the right type for each. The precision setting
is an integer, the fill setting is a character, and the flags setting is
a special type -- ios_base::fmtflags
// capture current output stream settings
int oldprecision = cout.precision();
char oldfill = cout.fill();
ios_base::fmtflags oldflags = cout.flags();
// do my output changes
cout.setf(ios::left);
cout << fixed;
cout << setprecision(1);
cout << setfill('x');
// print print print print
// etc etc etc etc
// PUT THINGS BACK THE WAY THEY WERE WHEN I FOUND THEM
cout.precision(oldprecision); // restore old precision setting
cout.fill(oldfill); // restore old fill char setting
cout.flags(oldflags); // restore all prior format flags
Code examples
Try running these two code examples, which do the same formatting
changes and printouts in main(), but also have a function that changes
some formats. The difference is that the first example doesn't put them
back the way they started, and the second one does. Look at the effect
on main's printouts!