C ++ FAQ Lite [15] - Enteroutput via <iostream> and <CSTDIO>

zhaozj2021-02-08  225

[15] Via and Enter / Output (Part of C FAQ Lite, Copyright © 1991-2001, Marshall Cline, Cline@parashift.com)

体,, nicrosoft @ sunistudio.com (East day production room, East day document)

FAQS in Section [15]:

[15.1] Why should not traditional ? [15.2] When typing illegal characters, why do I enter a dead cycle? [15.3] How to work with the blameless while (std :: cin >> foo)? [15.4] Why is my input processing exceed the end of the file? [15.5] Why after my program is in the first loop, will I ignore the input request? [15.6] How do I provide printing for CLASS FRED? [15.7] But can I always use the printon () method instead of a friend function? [15.8] How to input to CLASS FRED? [15.9] How to provide printing for the complete inheritance level? [15.10] How to "heavy open" std :: cin and std :: cout in the DOS and / or OS / 2 environment? [15.11] Why can't I open the file in a different directory such as "../test.dat"? [15.12] How to convert a value (such as, a number) to std :: string? [15.13] How to convert the std :: string into a value?

[15.1] Why should rather than traditional ? [Recently Renamed "Subclassable" to "inheritable" and revamped to use new-style headers (on 7/00). Click Here to Go to the next FAQ IN The "chain" of realt changes.]

Because enhances type security, it reduces error, enhances performance, expandable, and provides inheritance.

Printf () is good, SCANF () regardless of whether it may cause errors, it is still valuable, however, for C I / O (translation: I / O, input / output), their functions are very limited. C I / O (using << and >>) is: ") relative to C (using Printf () and scanf ()).

Better type security: Use , the compiler statically know the type of object being I / O. Instead, uses "%" domain to dynamically point out the type. Less error tendency: Use , without excess must be "%" that must be consistent with the object being I / O. Remove extra, mean to remove a class of errors. Scalable: C mechanism allows new user-defined types to be I / O without destroying existing code. (You can imagine, everyone's colleagues add new incompatible "%" domain to printf () and scanf (), what kind of chaos?!). Inheritance: C mechanism is built on a real class, such as std :: Ostream and Std :: istream. File * of has a true class, so it can be inherited. This means that you can have other users-defined things and their effects are similar, and it can do any strange and interesting things you need. You will automatically get the I / O code written by the users you don't know, and they don't need to know the "Extended Stream" class you wrote. [Top | bottom | Previous section] --------------------------------------- -----------------------------------------

[15.2] When typing illegal characters, why is my program enter the dead cycle? [Recently Changed SO It Uses New-Style Headers and The Std :: Syntax (on 7/00). Click Here To Go To The next FAQ in The "chain" of real ".]

For example, suppose you have the following code, read an integer from std :: cin:

#include int main () {std :: cout << "Enter Numbers Separated By Whitespace (use -1 to quit):"; int i = 0; while (i! = -1) {std :: cin >> i; // bad form - see the following comments std :: cout << "You Entered" << i << '/ n';}} This program does not check if the typed is a legitimate character. In particular, if someone type is not an integer (such as "x"), std :: CIN flows into "failure", and all the input attempts will return immediately without anything. In other words, the program enters the dead loop; if 42 is the last successful number, the program will print "You Entered 42" message repeatedly.

A simple way to check the legal input is to move the input request from the While cycle body to the control expression of the While loop, such as:

#include int main () {std :: cout << "Enter a number, or -1 to quit:"; int i = 0; while (std :: cin >> i) {// good form IF (i == -1) Break; std :: cout << "You Entered" << i << '/ n';}} This result is when you tap end-of-file, or type a non- When integers, or type -1, the While loop will exit. (Nature, you can also change the While cycle expression while (std :: cin >> i) && (i! = -1)), but this is not The focus of this FAQ, this FAQ is processed by IStream, not a general structured programming guide.)

[TOP | BOTTOM | Previous Section | Next Section]

-------------------------------------------------- ------------------------------

[15.3] How to work with the blameless while (std :: cin >> foo)? [Recently Changed SO It Uses New-Style Headers and The Std :: Syntax (on 7/00). Click Here To Go To The next FAQ in The "chain" of real ".]

"Weird While (std :: cin >> foo) grammar" see the previous FAQ.

(std :: cin >> foo) expression calls the appropriate Operator >> (for example, it calls the left with the std :: istream parameters, if the type is int, and there is an int & Operator >> on the right) . The std :: istream operator >> The function returns the parameters left on the left, here, it returns std :: cin. The next step is noted that the returned std :: istream is in a Boolean context, so the compiler converts std :: istream into a Boolean value.

The compiler calls a member function called std :: istream :: Operator void * () to convert std :: istream into Boolery. It returns a Void * pointer converted into Bur (NULL to become false, and any other pointer is TRUE). Therefore, the compiler generates the call of std :: cin.operator void * (), just like your icon (void *) std :: cin This explicitly enforces type conversion.

If the stream is in good condition, the conversion operator operator void * () returns a non-pointer, and if it is in a failed state, returns NULL. For example, if it is read too many times (that is, it is already in end-of-file), or the actual input to stream is not the legal type of FOO (eg, if foo is an int, and the data is a "x" Character), the stream will enter the failure and the conversion operator returns NULL.

Operator >> Not simply returns a BOOL (or void *) is why Success or failure is to support the "Cascade" syntax: std :: cin >> foo >> bar; operator >> is combined to the left It means that the code as above will be explained as:

(std :: cin >> foo) >> bar; otherwise, if we turn Operator >> to a normal function name, such as readfrom (), will change to such an expression:

Readfrom (ReadFrom (std :: cin, foo), bar); we always calculate expressions from the inside. Because of the left conjunction of Operator>, it becomes the leftmost expression std :: cin >> foo. This expression returns std :: cin (more appropriate, he returns a reference to the left parameter) to the next expression. The next expression also returns (a reference) to std :: cin, but the second reference is ignored because it is the outermost expression of this "expression statement".

[TOP | BOTTOM | Previous Section | Next Section]

-------------------------------------------------- ------------------------------

[15.4] Why is my input processing exceed the end of the file? [Recently Changed SO It Uses New-Style Headers and The Std :: Syntax (on 7/00). Click Here To Go To The next FAQ in The "chain" of real ".]

Because only after trying to exceed the file last, the EOF tag will be set. That is, when reading the last byte from the file, I have not set an EOF tag. For example, assume that the input stream is mapped to the keyboard - in this case, the C library is not possible to predict whether the characters typed in the user are the last character.

For example, the following code will have "exceed 1" error for the counter i:

INT i = 0; while (! std :: cin.eof ()) {// error! (Unreliable) std :: cin >> x; i; // Work with x ...} You do actually need:

INT i = 0; while (std :: cin >> x) {// correct! (Reliable) i; // Work with x ...} [top | bottom | Previous section | Next section]

-------------------------------------------------- ------------------------------

[15.5] Why after my program is in the first loop, will I ignore the input request? [Recently Changed SO It Uses New-Style Headers and The Std :: Syntax (on 7/00). Click Here To Go To The next FAQ in The "chain" of real ".]

Because the number of extractors retain non-numbers behind the input buffer.

If your code looks like this: char name [1000]; int Age; for (;;) {std :: cout << "name:"; std :: cin >> name; std :: cout << " Age: "; std :: cin >> Age;} and you do practical:

FOR (;;: cin >> age; std :: cin >> age; std :: cin >> age; std :: cin >> age; std :: cin >> Age; std :: cin >> (INT_MAX, '/ N'); This line skips non-digital characters.

[TOP | BOTTOM | Previous Section | Next Section]

-------------------------------------------------- ------------------------------

[15.6] How do I provide printing for CLASS FRED? [Recently Changed SO It Uses New-Style Headers and The Std :: Syntax (on 7/00). Click Here To Go To The next FAQ in The "chain" of real ".]

The operator Operator << is provided with an operator overload.

#include class fred {public: friend std :: ostream & operator << (std :: ostream & o, const fred & fred); // ... private: int i_; // just for illustrative}; std :: Ostream & Operator << (std :: ostream & o, const fred & fred) {return o << fred.i_;} int main () {fred f; std :: cout << "my fred object: << f << "/ n"; If the Fred object is expected to be in the left side of the << (that is, myfred << std :: cout instead of std :: cout << myfred), there will be a member function named Operator <<.

Note that Operator << returns the stream. This allows the output operator to be cascaded.

[TOP | BOTTOM | Previous Section | Next Section]

-------------------------------------------------- ------------------------------

[15.7] But can I always use the printon () method instead of a friend function? [Recently Created (on 7/00) And Fixed A Bug Thanks To Richard Hector (on 4/01). Click Here To Go To The Next FAQ in The "chain" of rencent changes.

Usually people are always willing to use the Printon () method rather than a friend function because they mistakely believe that the friend destroyed the package and / or the friend is poor. These faith are innocent and wrong: proper use, friend can actually enhance the package.

This is not said that the Printon () method is useless. For example, it is useful when providing printing for a complete inheritance level. But if you see a printon () method, it should usually be protected instead of public.

For complete, here "Printon () method" is given. The idea is a member function (often referred to as Printon () to complete the actual print, and then there is an operator << to call the Rinton () method). When it is incorrectly, the Printon () method is public, so the Operator << does not need to be a friend - it becomes a simple top function, ie not a class friend, is not a class member function. This is some sample code:

#include class fred {public: void printon (std :: ostream & o) const; // ...}; // Operator << can be declared as non-friendless [not recommended! ] Std :: ostream & operator << (std :: ostream & o, const fred & fred); // actually printed from the internal printon () method to complete [not recommended! ] Void Fred :: Printon (std :: ostream & o) const {// ...} // Operator << call printon () [Not recommended! ] Std :: ostream & operator << (std :: ostream & o, const fred & fred) {Fred.Printon (O); return O;} People mistakenly assume that "avoiding a friend function" is reduced to reduce maintenance costs . This assumption is wrong because:

On maintenance costs, the "top-level function call members" method will not bring any benefits. We assume that the N-line code is to complete the actual print. In the case of using a friend function, the N-line code will directly access the class's private / protected section, which means that someone will need to be scanned by anyone changed the Private / Protected section of the class, the N-line code will need to be scanned and may Modified, this increases maintenance costs. However, using the Printon () method does not change: We still have N-line code to directly access the classes of the Private / Protected section. Therefore, the code from the friend function moves to the member function does not reduce the maintenance cost. There is no reduction. There is no benefit on maintenance costs. (If any, the Printon () method is worse, because you have an extra original function, now there is more line code needs to be maintained) "Top-level function call members" method makes the class more difficult In particular, the programmer is not a class of designers. This method exposes one of the PUBLIC methods that is not desired to be called to the programmer. When the programmer read the PUBLIC method, they will see two methods to do the same thing. Document needs to be like this: "This is not exactly exactly, but don't use this; but should use that." And the usual programmer will say: "Oh? If I shouldn't use it, why is it public?" In fact, the Printon () method is the only reason for public, to avoid authorizing the friend to operator <<, this proposition Some programmers just want to use this class are subtle and difficult to understand. In short, "Top-level function call members" methods have cost, no benefits. Therefore, usually, not a good idea. Note: If the Printon () method is protected or private, the second objection will not be established. Some situations are reasonable, such as providing printing as a class with a complete inheritance level. Also note that when the Printon () method is non-public, Operator << needs to become a friend.

[TOP | BOTTOM | Previous Section | Next Section]

-------------------------------------------------- ------------------------------

[15.8] How to provide input for CLASS FRED? [Recently Changed SO It Uses New-Style Headers and The Std :: Syntax (on 7/00). Click Here To Go To The next FAQ in The "chain" of real ".]

Use the operator overload to provide an operator Operator >> of a friend's right switching. In addition to the parameters, there is no const: "Fred &" instead of "const fred &", other and output operators.

#include Class Fred {public: Friend Std :: istream & Operator >> (std :: istream & i, fred & fred); // ... private: int}; // just for illustrative}; std :: istream & Operator >> (std :: istream & i, fred & fred) {return I >> Fred.i_;} int main () {fred f; std :: cout << "Enter a Fred Object:"; std :: cin> > f; // ...} Note Operator >> Return to the stream. This allows the input calculator to be cascaded and / or in a loop or statement. [TOP | BOTTOM | Previous Section | Next Section]

-------------------------------------------------- ------------------------------

[15.9] How to provide printing for the complete inheritance level? [Recently Changed SO It Uses New-Style Headers and The Std :: Syntax (on 7/00). Click Here To Go To The next FAQ in The "chain" of real ".]

Provide a friend's Operator << call a protected virtual function:

Class base {public: friend std :: ostream & operator << (std :: ostream & o, const base); // ... protected: virtual void printon (std :: ostream & o) const;}; inline std :: Ostream & Operator << (std :: ostream & o, const base & b) {b.Printon (o); return o;} class derived: public base {protected: Virtual Void Printon (std :: ostream & o) const;}; final The result is that Operator << is like dynamic binding, even if it is a friend function. This is called "virtual friends".

Pay attention to the derived class to override Printon (std :: ostream &) const. In particular, they do not provide their own Operator <<.

Naturally, if Base is an ABC (Abstract base class), base :: printon (std :: ostream &) can be declared using the "= 0" syntax as a pure virtual function.

[TOP | BOTTOM | Previous Section | Next Section]

-------------------------------------------------- ------------------------------

[15.10] How to "heavy open" std :: cin and std :: cout in the DOS and / or OS / 2 environment? [Recently Changed So It Uses New-Style Headers and The Std :: Syntax (on 7/00). Click Here To Go To The next FAQ in The "chain" of rencent changes.] This depends on the implementation, please see your The documentation of the compiler.

For example, suppose you want to use std :: cin and std :: cout for binary I / O. Human your operating system (such as DOS or OS / 2) insists that "/ R / N" entered from std :: cin is translated into "/ N", which will output from std :: cout or std :: CERR " / N "translated into" / r / n ".

It is not a standard method that makes std :: cin, std :: cout and / or std :: CERR are opened in binary mode. Close the stream and try to turn them in binary mode, which may get undesired or undesirable results.

At the system's distinction, implementation may provide a way to make them binary stream, but you must see the manual to find.

[TOP | BOTTOM | Previous Section | Next Section]

-------------------------------------------------- ------------------------------

[15.11] Why can't I open a file in different directories such as "../test.dat"? [Recently Changed SO IT Uses New-Style Headers and Usees The Std :: Syntax (on 7/00). Click Here to Go To The Next FAQ in The "chain" of rencent changes.

Because "/ t" is a TAB character.

You should use a forward slash in the file, even in the operating system using a backslash, such as DOS, Windows, OS / 2, etc. E.g:

#include #include int main () {#if 1 std :: ifstream file ("../ Test.dat"); // correct! #ELSE std :: ifstream file ("../ Test.dat"); // Error! #ENDIF / / ...} Remember, the backslash ("/") is used to create special characters in the string: "/ n" is the wrap, "/ b" is back, and "/ t" Is a Tab, "/ a" is a warning (Alert), "/ v" is a vertical-tab. Therefore, the file name "/Version/next/alpha/beta/test.dat" is interpreted as a bunch of zone characters; should be replaced with "/version/next/alpha/beta/test.dat", even if the system is used "/" As a directory separator, such as DOS, Windows, OS / 2, etc. This is because the library routines in the operating system are switchable "/" and "/".

[TOP | BOTTOM | Previous Section | Next Section]

-------------------------------------------------- ------------------------------

[15.12] How to convert a value (such as, a number) to std :: string? [Recently created Thanks to Rob Stewart (on 7/00). Click Here to Go To The next FAQ in The "Chain" of Recent Changes .] There are two ways: you can use the tool or library. Usually, you should use the library.

library allows you to use the following syntax (convert an example of a double, but you can replace the wonderful anything to convert any wonderful things into std :: string: STRING:

#include #include #include std :: string converttotring (double x) {std :: ostringstream O; if (o << x) return o.str (); // This is some Error handle ... return "conversion error";} std :: OStringStream object O provides a formatting tool for std :: cout. You can use the manipulators and formatted flags to control the formatted results, just as you can do with std :: cout.

In this example, we insert X into O by an overloaded insertion operator <<. It calls the formatting tool for iostream to convert X to a std :: string. IF test guarantees the correct work - for built-in / inherent type, always succeeded, but IF test is a good style.

Expression OS.STR () returns std :: string of anything that is inserted into the stream O, here, is a string of the value of X.

[TOP | BOTTOM | Previous Section | Next Section]

-------------------------------------------------- ------------------------------

[15.13] How to convert std :: string into values? [Recently Created Thanks to Rob Stewart (on 7/00). Click Here to Go To The Next FAQ in The "chain" of real channel.]

There are two ways: you can use the tool or library. Usually, you should use the library.

library allows you to use the following syntax (convert an example of a Double, but you can replace the wonderful number of anything you can use >> Mode of action to convert a std :: string to wonderful anything:

#include #include #include Double convertfromstring (const st :: string & s) {std :: istringstream i (s); double x; if (i >> x) returnx x; // Some error handling here ... Return 0.0;} std :: istringstream object i provides a formatting tool similar to std :: cin. You can use the manipulators and formatted flags to control the formatted results, just as you can do with std :: cin. In this example, we pass Td :: String S to initialize std :: istringstream i (for example, S may be a string "123.456"), then we extract I To x. It calls the Iostream's formatting tool to perform as possible / appropriate X-type transitions on the string.

The IF test guarantees that the conversion works correctly. For example, if the string contains characters that are not suitable for X-type, the IF test will fail.

[TOP | BOTTOM | Previous Section | Next Section]

E-mail the author [C FAQ Lite | Table of Contents | Subject Index | About The Author | © | Download Your Own Copy] Revised Apr 8, 2001

转载请注明原文地址:https://www.9cbs.com/read-2072.html

New Post(0)