?? 11章 c++輸入輸出流.txt
字號:
C++大學教程(第11章 C++輸入/輸出流-01)
教學目標
●了解怎樣使用C++面向對象的輸入/輸出流
●能夠格式化輸入和輸出
●了解I/O流類的層次結構
●了解怎樣輸入/輸出用戶自定義類型的對象
●能夠建立用戶自定義的流操縱算子
●能夠確定/輸出操作的成功與失敗
●能夠把輸入輸出流連到輸人流上
11.1 簡介
C++標準庫提供了—組擴展的輸入/輸出(I/O)功能。本章將詳細介紹C++中最常用的一些I/O 操作,并對其余的輸入/輸出功能做一簡要的概述。本章的有些內容已經在前面提到,這里對輸入/輸出功能做一個更全面的介紹。
本章討論的許多輸入/輸出功能都是面向對象的,讀者會發現C++的I/O操作能夠實現許多功能。C++式的I/O中還大量利用了C++的其他許多特點,如引用、函數重載和運算符重載等等。
C++使用的是類型安全(typesafe)的I/O操作,各種I/O操作都是以對數據類型敏感的方式來執行的。假定某個函數被專門定義好用來處理某一特定的數據類型,那么當需要的時候,該函數會被自動調用以處理所對應的數據類型。如果實際的數據類型和函數之間不匹配,就會產生編譯錯誤。
因此,錯誤數據是不可能通過系統檢測的(C語言則不然。這是C語言的漏洞,會導致某些相當微妙而又奇怪的錯誤)。
用戶既可以指定自定義類型的I/O,也可以指定標準類型的I/O。這種可擴展性是C++最有價值的特點之一。
編程技巧11.1
盡管C語言式的I/O在C++中是可以使用的,但還是應該盡量使用C++特有的I/O格式。
軟件工程視點11.1
C++式的I/O是類型安全的。
軟件工程視點11. 2
C++允許對預定義類型和自定義類型的I/O用同樣的方法處理.從而可加快軟件的開發過程,特別是能夠提高軟件的復用性。
11.2 流
C++的I/O是以字節流的形式實現的,流實際上就是一個字節序列。在輸入操作中,字節從輸入設備(如鍵盤、磁盤、網絡連接等)流向內存;在輸出操作中,字節從內存流向輸出設備(如顯示器、打印機、磁盤、網絡連接等)。
應用程序把字節的含義與字節關聯起來。字節可以是ASCII字符、內部格式的原始數據、圖形圖像、數字音頻、數字視頻或其他任何應用程序所需要的信息。
輸人/輸出系統的任務實際上就是以一種穩定、可靠的方式在設備與內存之間傳輸數據。傳輸過程中通常包括一些機械運動,如磁盤和磁帶的旋轉、在鍵盤上擊鍵等等,這個過程所花費的時間要比處理器處理數據的時間長得多,因此要使性能發揮到最大程度就需要周密地安排I/O操作。一些介紹操作系統的書籍(見參考文獻Dc9O)深入地討論了這類問題。
C++提供了低級和高級I/O功能。低級I/O功能(即無格式I/O)通常只在設備和內存之間傳輸一些字節。這種傳輸過程以單個字節為單位.它確實能夠提供高速度并且可以大容量的傳輸,但是使用起來不太方便。
人們通常更愿意使用高級I/O功能(即格式化I/O)。高級I/O把若干個字節組合成有意義的單位,如整數、浮點數、字符、字符串以及用戶自定義類型的數據。這種面向類型的I/O功能適合于大多數情況下的輸入輸出,但在處理大容量的I/O時不是很好。
性能提示11.1
處理大容量文件最好使用無格式I/O。
11.2.1 iostream類庫的頭文件
C++的iostream類庫提供了數百種I/O功能,iostream類庫的接口部分包含在幾個頭文件中。
頭文件iostream.h包含了操作所有輸入/輸出流所需的基本信息,因此大多數C++程序都應該包含這個頭文件。頭文件iostream.h中含有cin、cout、cerr、clog 4個對象,對應于標準輸入流、標準輸出流、非緩沖和經緩沖的標準錯誤流。該頭文件提供了無格式I/O功能和格式化I/O功能。
在執行格式化I/O時,如果流中帶有含參數的流操縱算子,頭文件iomanip.h所包含的信息是有用的。
頭文件fstream.h所包含的信息對由用戶控制的文件處理操作比較重要。第13章將在文件處理程序中使用這個頭文件。
每一種C++版本通常還包括其他一些與I/O相關的庫,這些庫提供了特定系統的某些功能,如控制專門用途的音頻和視頻設備。
11.2.2 輸入/輸出流類和對象
iostream類庫包含了許多用于處理大量I/O操作的類。其中,類istream支持流輸入操作.類ostream支持流輸出操作,類iostream同時支持流輸入和輸出操作。
類istream和類ostream是通過單一繼承從基類ios派生而來的。類iostream是通過多重繼承從類istream和ostream派生而來的。繼承的層次結構見圖11.1。
運算符重載為完成輸入/輸出提供了一種方便的途徑。重載的左移位運算符(<<)表示流的輸出,稱為流插入運算符;重載的右移位運算符(>>)表示流的輸入,稱為流讀取運算符。這兩個運算符可以和標準流對象cin、cout、cerr、clog以及用戶自定義的流對象—起使用。
cin是類istream的對象,它與標準輸入設備(通常指鍵盤)連在一起。下面的語句用流讀取運算符把整數變量grade(假設grade為int類型)的值從cin輸入到內存中。
cin >> grade;
注意,流讀取運算符完全能夠識別所處理數據的類型。假設已經正確地聲明了grade的類型,那么沒有必要為指明數據類型而給流讀取運算符添加類型信息。
cout是類ostream的對象,它與標準輸出設備(通常指顯示設備)連在一起。下面的語句用流插入運算符cout把整型變量grade的值從內存輸出到標準輸出設備上。
cout << grade;
注意,流插入運算符完全能夠識別變量grade的數據類型,假定已經正確地聲明了該變量,那么沒有必要再為指明數據類型而給流插入運算符添加類型信息。
cerr是類osteam的對象,它與標準錯誤輸出設備連在一起。到對象cerr的輸出是非緩沖輸出,也就是說插入到cerr中的輸出會被立即顯示出來,非緩沖輸出可迅速把出錯信息告訴用戶。
clog是類ostream的對象,它與標準錯誤輸出設備連在一起。到對象clog的輸出是緩沖翰出。即每次插入clog可能使其輸出保持在緩沖區,要等緩沖區刷新時才輸出。
C++中的文件處理用類ifstream執行文件的輸入操作,用類ofstream執行文件的輸出操作,用類fstream執行文件的輸入/輸出操作。類ifstream繼承了類istream,類ofstream繼承了類ostream,類fstream繼承了類iostream。與I/O相關的類的繼承關系見圖11.2。雖然多數系統所支持的完整的輸入/輸出流類層次結構中還有很多類,但這里列出的類能夠實現多數程序員所需要的絕大部分功能。如果想更多地了解有關文件處理的內容,可參看C++系統中的類庫指南。
11.3 輸出流
C++的類ostream提供了格式化輸出和無格式輸出的功能。輸出功能包括:用流插入運算符輸出標準類型的數據;用成員函數put輸出字符;成員函數write的無格式化輸出(11.5節);輸出十
進制、八進制、十六進制格式的整數(11.6.1節);輸出各種精度的浮點數(11.6.2節)、輸出強制帶有小數點的浮點數(11.7.2節)以及用科學計數法和定點計數法表示的浮點數(11.7.6節);輸出在指定域寬內對齊的數據(11.7.3節);輸出在域寬內用指定字符填充空位的數據(11.7.4節);輸出科學計數法和十六進制計數法中的大寫字母(11.7.7節)。
11.3.1 流插入運算符
流插入運算符(即重載的運算符<<)可實現流的輸出。重載運算符<<是為了輸出內部類型的數據項、字符中和指針值。11.9節要詳細介紹如何用重載運算符<<輸出用戶自定義類型的數據項。
圖11.3中的范例程序用一條流插入語句顯示了輸出的字符串。圖11.4中的范例程序用多條流插入語句顯示輸出的字符串,該程序的運行結果與圖11.3中程序的運行結果相同。
1 // Fig. 11.3: figll 03.cpp
2 // Outputting a string using stream insertion.
3 #include <iostream.h>
4
56 int main()
7 cout << "Welcome to C++!\n";
8
9 return O;
10 }
輸出結果:
Welcome to C++!
圖 11.3 用一條流插入語句輸出字符串
1 // Fig. 11.4: figllO4.cpp
2 // Outputting a string using two stream insertions.
3 #include <iostream.h>
4
5 int main()
6{
7 cout << "Welcome to ";
8 cout << "C++!\n";
9
10 return 0;
11 }
輸出結果:
Welcome to C++!
圖 11.4 用兩條流插入語句輸出字符串
也可以用流操縱算子endl(行結束)實現轉義序列\n(換行符)的功能(見圖11.5)。流操縱算子endl發送一個換行符并刷新輸出緩沖區(不管輸出緩沖區是否已滿都把輸出緩沖區中的內容立即輸出)。也可以用下面的語句刷新輸出緩沖區:
cout << flush;
11.6節要詳細討論流操縱算子。
1 // Fig. 11.5: fig11_05.cpp
2 // Using the endl stream manipulator.
3 #include <iostream.h>
4
5 int main{)
6 {
7 cout << "Welcome to ";
8 cout << "c++!';
9 cout << endl; // end line stream manipulator
10
11 return 0;
12 }
輸出結果:
Welcome to C++!
圖 11.5 使用流操縱算子endl
流插入運算符還可以輸出表達式的值(見圖11.6)
1 // Fig. 11.6: fig11_O6.cpp
2 // Outputting expression values.
3 #include <iostream.h>
4
5 int main()
6 {
7 cout << "47 plus 53 is ";
8
9 // parentheses not needed; used for clarity
10 cout << ( 47 + 53 ); // expression
11 cout << endt;
12
13 return O;
14 }
輸出結果:
47 plus 53 is 100
圖 11.6 輸出一個表達式的值
編程技巧11.2
當輸出表達式時,為防止表達式中的運算符與運算符<<之間存在運算符化先級問題,用括號將表達式括起來。
11.3.2 連續使用流插入/流讀取運算符
重載的運算符<<和>>都可以在一條浯句中連續使用(見圖11.7)。
1 file:// Fig.11.7: fig11_07.cpp
2 file:// Cascadlng the overlOadGd << OPeratOr.
3 #includc<iostream.h>
4
5 int main()
6 {
7 cout << "47 plus 53 is " << ( 47 + 53 ) << endl;
8
9 return O;
10 }
輸出結果:
47 plus 53 is 100
圖 11.7 連續使用重載運算符<<
圖中多次使用流插入運算符的語句等同于下面的語句:
((( cout << " 47 plus 53 is " ) << 47 + 53 ) << endl);
之所以可以使用這種寫法,是因為重載的運算符<<返回了對其左操作數對象(即cout)的引用,因此最左邊括號內的表達式:
( cout << " 47 plus 53 is " )
它輸出一個指定的字符串,并返回對cout的引用,因而使中間括號內的表達式解釋為:
( cout << ( 47 + 53 ) )
它輸出整數值100,并返回對cout的引用。于是最右邊括號內的表達式解釋為:
cout << endl;
它輸出一個換行符,刷新cout并返回對cout的引用。最后的返回結果未被使用。
11.3.3 輸出char*類型的變量
C語言式的I/O必須要提供數據類型信息。C++對此作了改進,能夠自動判別數據類型。但是,C++中有時還得使用類型信息。例如,我們知道字符串是char*類型,假定需要輸出其指針的值,即字符串中第一個字符的地址,但是重載運算符<<輸出的只是以空(null)字符結尾的char*類型的字符串,因此使用void*類型來完成上述需求(需要輸出指針變量的地址時都可以使用void*類型)。圖11.8中的程序演示了如何輸出char*類型的字符串及其地址,輔出的地址是用十六進制格式表示。在C++中,十六進制數以0x或0X打頭,11.6.1節、11.7.4節、11.7.5節和11.7.7節要詳細介紹控制數值基數的方法。
1 // Fig. 11.8: fig11_08.cpp
2 // Printing the address stored in a char* variable
3 #include <iostream.h>
4
5 int main()
6{
7 char *string = "test";
8
9 cout << "Value of string is: "<< string
10 << "\nValue of static cast< void *>( string ) is:"
11 << static_cast< void*>( string )<<endl;
12 return 0;
13}
輸出結果:
Value of string is:test
Value of staticcast <void*>( string )is:Ox00416D50
圖 11.8 輸出char*類型變量的地址
11.3.4 用成員函數put輸出字符和put函數的連續調
用put成員函數用于輸出一個字符,例如語句:
cout.put('A');
將字符A顯示在屏幕上。
也可以像下面那樣在一條語句中連續調用put函數:
cout.put('A').put('\n');
該語句在輸出字符A后輸出一個換行符。和<<一樣,上述語句中圓點運算符(.)從左向右結合,put
成員函數返回調用put的對象的引用。還可以用ASCII碼值表達式調用put函數,語句cout.put(65)也
輸出字符A。
11. 4 輸入流
下面我們要討論流的輸入,這是用流讀取運算符(即重載的運算符>>)實現的。流讀取運算符通常會跳過輸人流中的空格、tab鍵、換行符等等的空白字符,稍后將介紹如何改變這種行為。當遇到輸入流中的文件結束符時,流讀取運算符返回0(false);否則,流讀取運算符返回對調用該運算符的對象的引用。每個輸入流都包含一組用于控制流狀態(即格式化、出錯狀態設置等)的狀態位。當輸入類型有錯時,流讀取運算符就會設置輸人流的failbit狀態位;如果操作失敗則設置badbit狀態位,后面會介紹如何在I/O操作后測試這些狀態位。11.7節和11.8節詳細討論了流的狀態位。
11.4.1 流讀取運算符
圖11.9中的范例程序用cin對象和重載的流讀取運算符>>讀取了兩個整數。注意流讀運算符可以連續使用。
1 // Fig. 11.9: figll_09.cpp
2 // Calculating the sum of two integers input from the keyboard
3 // with the cin oct and the stream-extraction operator.
4 #include <iostream.h>
5
6 int main()
7{
8 int x, y;
9
10 cout << "Enter two integers: ";
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -