C++IO流,istream status(状态位),cout,cin,if(非fs)/while(cin)【C++IO流】(58)
- IO流
- IO流類
- Hierarchy(層次架構)
- 流類特性(從ios繼承下來的共有的特性)
- 不可賦值和復制
- 緩沖
- 重載了<< >>
- istream status(狀態位)
- 狀態位的意義
- ios_base.h 中的狀態位
- 狀態位操作函數
- 測試與結論
- 結論
- 應用
- cout
- 格式輸出
- 成員函數
- cin
- >>
- get
- 聲明
- get()/get(&)
- get(s,n)/get(s,n,d)
- 小結
- getline
- 聲明
- 測試
- cin輸入字符串中的空格
- other
- 聲明
- 測試
- if(!fs)/while(cin)
- 合法性
- operator void*()與 與 operator!()
- 常見策略
- 自測
IO流
cin 和 cout 充當了 scanf 和 printf 的功能。
但他們并不是函數,而是類對象。
那么我們就有必要了解一下,他們是哪些類的對象。
IO流類
Hierarchy(層次架構)
cin是isream的對象,cout是ostream的對象。
流類特性(從ios繼承下來的共有的特性)
不可賦值和復制
fstream也是上面類中繼承的一種。
我們之前使用:
ostream & out 這里是 & 因為cin和cout都是全局的,所以我們在博客中說是沒有必要賦值一份,實際上想要復制也是不能實現的,因為是不能賦值和復制的。
凡是上面給出的繼承ios體系結構,都遵循不能賦值不能復制的規則。
代碼演示:
#include <iostream> #include <fstream> using namespace std;void foo(fstream fs) {} int main() {fstream fs1, fs2;fs1 = fs2; //報錯,不允許賦值foo(fs); //報錯,不允許復制return 0; }解釋:
上面賦值運算符重載和拷貝構造成員被private私有化,所以不允許賦值和拷貝。
不同于標準庫其他 class 的"值語意",iostream 是"對象語意",即 iostream 是non-copyable。這是正確的,因為如果 fstream 代表一個文件的話,拷貝一個 fstream 對象意味著什么呢?表示打開了兩個文件嗎?如果銷毀一個 fstream 對象,它會關閉文件句柄,那么另一個 fstream copy 對象會因此受影響嗎?
C++ 同時支持"數據抽象"和"面向對象編程",其實主要就是"值語意"與"對象語意"的區別,標準庫里的 complex<> 、pair<>、vector<>、 string 等等都是值語意,拷貝之后就與原對象脫離關系,就跟拷貝一個 int 一樣。而我們自己寫的 Employee class、TcpConnection class 通常是對象語意,拷貝一個 Employee 對象是沒有意義的,一個雇員不會變成兩個雇員,他也不會領兩份薪水。拷貝 TcpConnection 對象也沒有意義,系統里邊只有一個 TCP 連接,拷貝 TcpConnection 對象不會讓我們擁有兩個連接。因此如果在 C++ 里做面向對象編程,寫的 class 通常應該禁用 copy constructor 和 assignment operator。
緩沖
下面幾種情況會導致刷緩沖
1,程序正常結束,作為 main 函數結束的一部分,將清空所有緩沖區。
2,緩沖區滿,則會刷緩沖。
3,endl, flush 也會刷緩沖。
對比C語言printf函數刷新緩沖進行理解。
重載了<< >>
#include <iostream> #include <fstream> using namespace std; int main() {fstream fs("abc.txt", ios::in | ios::out | ios::trunc); //trunc等價于C語言文件操作w+if (!fs)cout << "open error" << endl;fs << 1 << " " << 2 << " " << 3;fs.seekg(0, ios::beg);int x, y, z;fs >> x >> y >> z;cout << x << y << z;return 0; }運行結果為:
所有的流類都重載了<<和>>
istream status(狀態位)
狀態位的意義
大部分情況下,我們可能并不關心這些標志狀態位,比如我們以前用到的 cin/cout。
但是在循環讀寫中,這些標志位確實有大用途。比如,用于判斷文件結束標志的位。
ios_base.h 中的狀態位
/// Indicates a loss of integrity in an input or output sequence (such /// as an irrecoverable read error from a file). static const iostate t badbit = _S_badbit; /// Indicates that an input operation reached the end of an input sequence. static const iostate t eofbit = _S_eofbit; /// Indicates that an input operation failed to read the expected /// characters, or that an output operation failed to generate the /// desired characters. static const iostate t failbit = _S_failbit; /// Indicates all is well. static const iostate t goodbit = _S_goodbit;狀態位操作函數
測試與結論
測試(通過成員函數來訪問)
#include <iostream> using namespace std; int main() {int val;cout << "Before a bad input operation:"<< "\n cin.eof() : " << cin.eof()<< "\n cin.fail(): " << cin.fail()<< "\n cin.bad() : " << cin.bad()<< "\n cin.good(): " << cin.good() << endl;cin >> val; // control + D/Z or 'a'cout << "After a bad input operation:"<< "\n cin.eof() : " << cin.eof()<< "\n cin.fail(): " << cin.fail()<< "\n cin.bad() : " << cin.bad()<< "\n cin.good(): " << cin.good() << endl;cin.clear(); //標志位清空cout << "\n cin.eof() : " << cin.eof()<< "\n cin.fail(): " << cin.fail()<< "\n cin.bad() : " << cin.bad()<< "\n cin.good(): " << cin.good() << endl;return 0; }運行結果為:
我們進行其他輸入測試:
輸入浮點類型數據沒有問題。因為讀取到的也是4個字節沒有問題。
輸入字符出現錯誤。字符所占1個字節,讀取的時候讀取4個字節,發生越界。
結論
bad 一般指的是硬件錯誤,不常用。
應用
#include <iostream> using namespace std; int main() {char ch;while(cin.get(ch),!cin.eof()){cout<<ch<<endl;}return 0; }運行結果為:
cout
格式輸出
成員函數
#include <iostream> #include <fstream> using namespace std; int main() {cout.put('a');cout.write("abcd", 2) << endl; //里面數字不能越界cout << 'a' << "abcd" << endl;return 0; }運行結果為:
上面函數基本不會使用到,我們更多的會直接使用cin
cin
>>
#include <iostream> using namespace std; int main() {char ch;while (cin >> ch) //通過返回值判斷真假{cout << ch << endl;}return 0; }運行結果為:
get
聲明
get()/get(&)
#include <iostream> using namespace std; int main() {char ch;while ((ch = cin.get()) != EOF){cout << ch << endl;}while (cin.get(ch)){cout << ch << endl;}return 0; }運行結果為:
get(s,n)/get(s,n,d)
#include <iostream> using namespace std; int main() {char buf[10];while (cin.get(buf, 2)) //終止符為’\n’{cout << buf << endl;}return 0; }運行結果為:
運行結果為:
小結
get 讀取字符,遇到 eof 則退出。get 最多讀到 n-1 個字符,遇到標志位或 eof,則退出。 越不過標志位。
上面兩個設置結束標志’\n’和’x’的函數遇到\n和x會直接退出,不會再次循環。所以我們引入下面函數。
getline
聲明
測試
#include <iostream> using namespace std; int main() {char buf[10];while (cin.getline(buf, 10,'x')){cout << buf << endl;}cout << "\ncin.eof() : " << cin.eof()<< "\ncin.fail(): " << cin.fail()<< "\ncin.bad() : " << cin.bad()<< "\ncin.good(): " << cin.good() << endl;return 0; }運行結果為:
上面代碼運行過程中,如果輸入標志位之前的數據個數小于設置讀取的最小個數,則會讀取輸入的數據并且跳過標志位繼續讀取,如果輸入標志位之前的數據個數大于設置讀取的最大個數,則會直接退出程序。
#include <iostream> using namespace std; int main() {char buf[10];while (cin.getline(buf, 10)){cout << buf << endl;}cout << "\ncin.eof() : " << cin.eof()<< "\ncin.fail(): " << cin.fail()<< "\ncin.bad() : " << cin.bad()<< "\ncin.good(): " << cin.good() << endl;return 0; }運行結果為:
在讀取 n-1 個字符前,遇到標志位,則會讀到標志位前的字符。然后越過標志位繼續讀取。
若在讀到 n-1 個字符前沒有遇到標志位,則會退出。
也就說如果輸入的字符個數小于讀取的字符個數那么就會直接讀取讀取并且跳過標志位,如果輸入的字符多于讀取的個數則會退出。
cin輸入字符串中的空格
之前我們使用cin輸入字符串就會出現這樣的問題:
#include <iostream> using namespace std; int main() {char buf[10];cin >> buf;cout << buf << endl;return 0; }運行結果為:
但是如果使用下面方式:
#include <iostream> using namespace std; int main() {char buf[10];cin.getline(buf,10);cout << buf << endl;return 0; }運行結果為:
other
聲明
測試
#include <iostream> using namespace std; int main() {char ch[20];cin.get(ch, 20, '/'); // i like c/ i like C++ also/cout << "the first part is :" << ch << endl;cin.get(ch, 20, '/'); // i like c/ i like C++ also/cout << "this second part is :" << ch << endl;return 0; }運行結果為:
我們可以看到get遇到/會直接結束。
#include <iostream> using namespace std; int main() {char ch[20];cin.getline(ch, 20, '/'); // i like c/ i like C++ also/cout << "the first part is :" << ch << endl;cin.getline(ch, 20, '/'); // i like c/ i like C++ also/cout << "this second part is :" << ch << endl;return 0; }運行結果為:
get 越不過去的截止字符,getline 越過丟棄的截止字符,如何作一些,補償措施呢?
#include <iostream> using namespace std; int main() {char ch[20];cin.get(ch, 20, '/'); // i like c/ i like C++ also/cout << "the first part is :" << ch << endl;cin.ignore(10, 'i'); //第一次讀取到/之后,忽略,直到遇到i位置沒并且連i也忽略掉。cin.get(ch, 20, '/'); // i like c/ i like C++ also/cout << "this second part is:" << ch << endl;return 0; }運行結果為:
#include <iostream> using namespace std; int main() {char ch[20];cin.get(ch, 20, '/'); // i like c/ i like C++ also/cout << "the first part is :" << ch << endl;cin.ignore(10, 'i'); //第一次讀取到/之后,往后忽略10個字節,//直到遇到i位置沒并且連i也忽略掉。cin.putback('i');//忽略i之后再使用cin.putback('i');把忽略的i推進去。char peek = cin.peek(); //窺探一下,不影響底層指針的走動cout << "peek is :" << peek << endl; //打印窺探結果cin.get(ch, 20, '/');cout << "this second part is:" << ch << endl;return 0; }運行結果為:
if(!fs)/while(cin)
#include <iostream> #include<fstream> using namespace std; int main() {fstream fs("cc.txt",ios::in); //只有讀取文件的權限,沒有創建文件的權限if (!fs) //!重載 等價于fs.operator!(){cout << "open error" << endl;}return 0; }運行結果為:
#include <iostream> #include<fstream> using namespace std; int main() {char ch;//等價于while(cin>>ch,!cin.fail()) 也等價于while(cin)while (cin >> ch) {cout << ch << endl;}return 0; }運行結果為:
上面代碼中,體現出cin可以轉化為bool,int,void * 等類型。對象自身發生轉化。
當是一個對象的時候就會根據已經自身發生一個轉化,轉化函數,重載都要根據語境調用發生適當的轉化。
合法性
在判斷文件打開成功與否或是連續從流中讀取數據時,就要用到對流對象的操作,比如 if(!fs)和 while(cin>>val),我們都知道 cin 是一個流對象,而>>運算符返回左邊的流對象,也就是說 cin>>val 返回 cin,于是 while(cin>>val)就變成了 while(cin),問題就變成了一個流對象在判斷語句中的合法性。
不管是 while(cin)還是 if(!fs),都是合法的,為什么呢?
我們自己定義一個類,然后定義該類的對象,然后使用 if 語句來判斷它是不合法的。
這說明,流對象具有某種轉換函數,可以將一個流對象轉換成判斷語句可以識別的類型
operator void*()與 與 operator!()
打開 iostream.h 文件,找到 cin 的定義,發現是來自于 istream.h,其中的模板類basic_istream 繼承自 basic_ios,打開 basic_ios 的定義,發現它有兩個重載函數。 operator void *() const 和operator!() const。這兩個函數使得流對象可作為判斷語句的內容。
/** * @brief The quick-and-easy status check. * * This allows you to write constructs such as * <code>if (!a_stream) ...</code> and <code>while(a_stream) ...</code> *///數 轉化函數 A A 類對象> -> d void * * 對象 operator void*() const {return this->) fail() ? 0 : const_cast<basic_ios*>(this); }// 運算符重載數 函數 用 對象調用 operator! bool operator! !() const () {return this-> fail(); }常見策略
//while the stream is OK while(cin) = => while(!cin.fail()) //if the stream is NOT OK if(!cin) = => if(cin.fail())自測
#include<iostream> using namespace std;class A { public:A() {}~A() {}operator void* ()const //轉化函數 A類對象? void * 對象{cout << "operator void* () cast to void*; ";return (void*)this;}//運算符重載函數 對象調用 operator! bool operator!() const (){cout << "bool operator!() return bool; ";return true;} }; int main() {A a;if (a) cout << "first" << endl;if (!a) cout << "second" << endl;return 0; }運行結果為:
總結
以上是生活随笔為你收集整理的C++IO流,istream status(状态位),cout,cin,if(非fs)/while(cin)【C++IO流】(58)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++异常处理,Error,C和C++
- 下一篇: C++模板:模板简述,函数模板详细说明【