|
![]() |
|||
![]() |
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
![]() |
![]() |
[an error occurred while processing this directive]
Steps
How It Works Stream operations get their relatively easy-to-learn syntax from the fact that they return stream objects themselves (whose functions can be called, and so on). Manipulators use this syntax too, and that makes it possible to easily hook in in-stream formatting style manipulators when convenient. The advantages of this technique are
The following code listing, usrmanip.cpp, shows how to use non-parameterized manipulators: // File: usrmanip.cpp // Example for C++ How-To // Writing your own stream manipulators // Copyright 1998, Jan Walter // NO WARRANTY. If this code breaks you get to keep both pieces. // Compiler verificiation: // Borland C++ 5.01A: Yes // DJGPP 2.01 w. GCC 2.81 : Yes // Watcom 10.5: Not Tried // Microsoft VC++ 5: Not Tried // GCC 2.7.2/Linux: Not tried // GCC/EGCS/Linux: Not tried // This sample program details how to write your own streams manipulators. // While it is only possible to write manipulators that dont take parameters // without modifying the actual streams source code (which is beyond the // scope of this book), the advantages of having only one function to set // a stream to the way its needed (and another to return it to its original // state) are many: its easier, more clearer for others to understand, and // less likely to result in program bugs or undesired behavior. // In this example we will use non-parameterized IO manipulators to set the // width of numerical output and the alignment of numerical output in one // operation. This technique can be combined with overloaded insertion and // extraction operators to make code more readable and less susceptible to // oversights (i.e. bugs and side effects). // What the program itself does: // This program reads standard input for numbers as fractions, numerator and // then denominator, interpreted as fractions of the angle of full circle // (i.e. 360 degrees) and converts those to the angle in degrees. For example, // 25 100 (meaning the fraction of 25 over 100) would be 90 degrees. // // The best way to feed data to a program of this type is to put all of the // numbers into a text file, and then redirect the file into the programs // standard input using the operating system shells redirection symbol. // i.e. usrmanip < angles.txt // // If you choose to enter fractions manually, the letter Ctrl-Z is the // end-of-file character and will denote to the program that youre finished // entering data. #include <iostream.h> #include <iomanip.h> #ifdef __BORLANDC__ #pragma hdrstop #endif #include <string> // The program will define 2 manipulators - one that configures the stream // to the way we want it for output, and the other one to append some text and // set it back to the way it was. ostream& setfmt( ostream& output ) { output << setw( 9 ) ; output.setf( ios:: right ) ; return output ; } ostream& unsetfmt( ostream& output ) { output << setw( 0 ) ; output.unsetf( ios:: right ) ; output << degrees. ; return output ; } // the class degree abstracts the io and error handling for the reading, // writing, and calculations of this program. // degrees in a full circle. const double maxdegrees = 360 ; class degree { private: double numerator ; double denominator ; public: // constructors: the default constructor, an initialized constructor, // and a copy constructor degree() : numerator(0), denominator(0) {} degree( double num, double dem ) { numerator = num ; denominator = dem ; } // technically, a copy constructor is not required in this case, since // compilers will generate a memberwise copy constructor in cases like this. // However, anytime arrays are involved, a copy constructor must be defined, // since assignment of one array to another actually only copies the address // of the array, and not the contents. Then it becomes a race to see which // instance of the class deallocates the memory for the array first - the // second time the now invalid array gets deallocated the operating system // will terminate the program with a GPF (Windows, Win32, OS/2) or a // segmentation fault (UNIX, Linux). // // This being said, its good practice to include one anyway. degree ( degree& copyfrom ) { numerator = copyfrom.numerator ; denominator = copyfrom.denominator ; } // overloaded assignment operator degree& operator=( const degree& copyfrom ) { numerator = copyfrom.numerator ; denominator = copyfrom.denominator ; return *this ; } // validity operator ! - dividing by zero is an illegal operation from the // computers point of view, so we check for this possibility using the // NOT operator bool operator!() const { if( denominator == 0.0 ) return true ; return false ; } // this returns the actual degrees double val() const { if( !*this ) // check to see if our data is valid return 0.0 ; return numerator / denominator * maxdegrees ; } }; // overloaded stream extraction and insertion operators istream& operator>>( istream& is, degree& read ) { double a, b ; is >> a >> b ; read = degree(a, b); return is ; } // decision time: we could put the io manipulators into the output stream // instead, if we wanted to. ostream& operator<<( ostream& os, const degree& write ) { if( !write ) // data is not valid os << Error! ; else os << setfmt << write.val() << unsetfmt ; return os ; } // the main function actually does the IO handling and printing of the // copyright. int main( int, char** ) { // the cerr output stream does not get redirected by default, // so its used to print messages that have to make it though to the user cerr << Fraction to angle calculator. << endl << (c) Jan Walter, 1998. NO WARRANTY. << endl ; degree mydegree ; int count = 1 ; cin >> mydegree ; while( cin ) { cout << Reading << count++ << : << mydegree << endl ; cin >> mydegree ; } } // end of file Comments Using custom I/O manipulators can make code more readable, more trouble-free, and also more maintainable. This is probably one of the least-exploited features of the iostreams library. Another advantage is that your programs output will be more consistent. The criteria I use is that if I have to repeat a formatting sequence more than three times for a given type of data, its worth my time to put the sequence into a custom modifier to ensure that the output of the program will be more consistent.
|
![]() |
Products | Contact Us | About Us | Privacy | Ad Info | Home
Use of this site is subject to certain Terms & Conditions, Copyright © 1996-1999 EarthWeb Inc. All rights reserved. Reproduction whole or in part in any form or medium without express written permision of EarthWeb is prohibited.
|