C++基礎教程面向物件(學習筆記(103))
使用ostream和ios輸出
在本節中,我們將介紹iostream輸出類(ostream)的各個方面。
注意:本課程中的所有I / O功能都位於std名稱空間中。這意味著所有I / O物件和函式都必須以“std ::”為字首,或者必須使用“using namespace std;”語句。
插入操作符
插入運算子(<<)用於將資訊放入輸出流。C ++為所有內建資料型別預定義了插入操作,您已經瞭解瞭如何為自己的類過載插入操作符。
在關於流的課程中,您看到istream和ostream都來自一個名為ios的類。ios(和ios_base)的一個工作是控制輸出的格式化選項。
格式化
有兩種方法可以更改格式選項:標誌和操縱器。您可以將標誌視為可以開啟和關閉的布林變數。 操縱器是放置在流中的物件,它影響輸入和輸出的方式。
要開啟標誌,請使用setf()函式,並將相應的標誌作為引數。例如,預設情況下,C ++不會在正數前面列印+號。但是,通過使用std :: showpos標誌,我們可以更改此行為:
std::cout.setf(std::showpos); // 開啟std :: showpos標誌
std::cout << 27 << '\n';
這導致以下輸出:
+27
可以使用OR(|)運算子一次開啟多個ios標誌:
std::cout.setf(std::showpos | std::uppercase); //開啟std :: showpos和std :: uppercase標誌
std::cout << 27 << '\n';
要關閉標誌,請使用unsetf()函式:
std::cout.setf(std::showpos); //開啟std :: showpos標誌 std::cout << 27 << '\n'; std::cout.unsetf(std::showpos); //關閉std :: showpos標誌 std::cout << 28 << '\n';
這導致以下輸出:
+27
28
當使用需要提及的setf()時,還有一點棘手。許多標誌屬於組,稱為格式組。格式組是一組執行類似的(有時相互排斥)格式化選項標誌。例如,名為“basefield”的格式組包含標誌“oct”,“dec”和“hex”,它們控制整數值的基數。預設情況下,設定“dec”標誌。因此,如果我們這樣做:
std::cout.setf(std::hex); // 嘗試開啟十六進位制輸出
std::cout << 27 << '\n';
我們得到以下輸出:
27
它沒用!原因是因為setf()只打開了標誌 - 它不夠聰明,無法關閉互斥標誌。因此,當我們開啟std :: hex時,std :: dec仍然開啟,並且std :: dec顯然優先。有兩種方法可以解決這個問題。
首先,我們可以關閉std :: dec,以便只設置std :: hex:
std::cout.unsetf(std::dec); //關閉十進位制輸出
std::cout.setf(std::hex); // 開啟十六進位制輸出
std::cout << 27 << '\n';
現在我們按預期獲得輸出:
1b
第二種方法是使用另一種形式的setf(),它接受兩個引數:第一個引數是要設定的標誌,第二個引數是它所屬的格式化組。使用這種形式的setf()時,屬於該組的所有標誌都將被關閉,並且只有傳入的標誌才會開啟。例如:
// 開啟std :: hex作為唯一的std :: basefield標誌
std::cout.setf(std::hex, std::basefield);
std::cout << 27 << '\n';
這也產生了預期的輸出:
1b
使用setf()和unsetf()往往很尷尬,因此C ++提供了另一種更改格式選項的方法:操縱器。關於操縱器的好處是它們足夠聰明,可以開啟和關閉相應的標誌。以下是使用一些操縱器來更改基礎的示例:
std::cout << std::hex << 27 << '\n'; // 以十六進位制列印27
std::cout << 28 << '\n'; // 我們還是十六進位制
std::cout << std::dec << 29 << '\n'; // 回到小數
該程式產生輸出:
1b
1c
29
通常,使用操縱器比設定和取消設定標誌要容易得多。通過標誌和操縱器可以獲得許多選項(例如更改基礎),但是,其他選項只能通過標記或操縱器獲得,因此瞭解如何使用它們非常重要。
有用的格式化程式
這是一些更有用的標誌,操縱器和成員函式的列表。標誌存在於ios類中,操縱符存在於std名稱空間中,成員函式存在於ostream類中。
Group | Flag | 含義 |
---|---|---|
boolalpha | 如果設定,則布林值列印“true”或“false”。如果未設定,則布林值列印0或1 |
Manipulator | 含義 |
---|---|
boolalpha | 布林列印“真實”或“虛假” |
noboolalpha | 布林值列印0或1(預設) |
例:
std::cout << true << " " << false << '\n';
std::cout.setf(std::boolalpha);
std::cout << true << " " << false << '\n';
std::cout << noboolalpha << true << " " << false << '\n';
std::cout << boolalpha << true << " " << false << '\n';
結果:
1 0
true false
1 0
true false
Group | Flag | 含義 |
---|---|---|
showpos | 如果設定,則使用+字首正數 |
Manipulator | 含義 |
---|---|
showpos | 使用+字首正數 |
noshowpos | 不使用+字首正數 |
例:
std::cout << 5 << '\n';
std::cout.setf(std::showpos);
std::cout << 5 << '\n';
std::cout << noshowpos << 5 << '\n';
std::cout << showpos << 5 << '\n';
結果:
5
+5
5
+5
Group | Flag | 含義 |
---|---|---|
大寫 | 如果設定,則使用大寫字母 |
Manipulator | 含義 |
---|---|
大寫 | 使用大寫字母 |
小寫 | 使用小寫字母 |
例:
std::cout << 12345678.9 << '\n';
std::cout.setf(std::uppercase);
std::cout << 12345678.9 << '\n';
std::cout << nouppercase << 12345678.9 << '\n';
std::cout << uppercase << 12345678.9 << '\n';
結果:
1.23457e + 007
1.23457E + 007
1.23457e + 007
1.23457E + 007
Group | Flag | 含義 |
---|---|---|
basefield | dec | 以十進位制列印值(預設) |
basefield | hex | 以十六進位制列印值 |
basefield | oct | 以八進位制列印值 |
basefield | (none) | 根據值的前導字元列印值 |
Manipulator | 含義 |
---|---|
dec | 以十進位制列印值 |
hex | 以十六進位制列印值 |
oct | 以八進位制列印值 |
例:
std::cout << 27 << '\n';
std::cout.setf(std::dec, std::basefield);
std::cout << 27 << '\n';
std::cout.setf(std::oct, std::basefield);
std::cout << 27 << '\n';
std::cout.setf(std::hex, std::basefield);
std::cout << 27 << '\n';
std::cout << std::dec << 27 << '\n';
std::cout << std::oct << 27 << '\n';
std::cout << std::hex << 27 << '\n';
結果:
27
27
33
1b
27
33
1b
到現在為止,您應該能夠看到通過標誌和操縱器設定格式之間的關係。在將來的示例中,我們將使用操縱器,除非它們不可用。
精度,符號和小數點
使用操縱器(或標誌),可以更改顯示浮點數的精度和格式。有幾種格式化選項以複雜的方式組合,因此我們將仔細研究這一點。
Group | Flag | 含義 |
---|---|---|
floatfield | fixed | 對浮點數使用十進位制表示法 |
floatfield | scientific | 對浮點數使用科學記數法 |
floatfield | (none) | 固定用於少數位的數字,否則為科學 |
floatfield | showpoint | 始終顯示小數點,併為浮點值尾隨0 |
Manipulator | 含義 |
---|---|
fixed | 對值使用十進位制表示法 |
scientific | 使用科學記數法表示值 |
showpoint | 顯示小數點,併為浮點值尾隨0 |
noshowpoint | 對於浮點值,不顯示小數點和尾隨0 |
setprecision(int) | 設定浮點數的精度(在iomanip.h中定義) |
成員函式 | 含義 |
---|---|
precision()返回浮點數的當前精度 | |
sprecision(int) | 使設定浮點數的精度並返回舊精度 |
如果使用固定或科學記數法,精度將確定顯示分數中的小數位數。請注意,如果精度小於有效位數,則數字將被舍入。
std::cout << std::fixed << '\n';
std::cout << std::setprecision(3) << 123.456 << '\n';
std::cout << std::setprecision(4) << 123.456 << '\n';
std::cout << std::setprecision(5) << 123.456 << '\n';
std::cout << std::setprecision(6) << 123.456 << '\n';
std::cout << std::setprecision(7) << 123.456 << '\n';
std::cout << std::scientific << '\n';
std::cout << std::setprecision(3) << 123.456 << '\n';
std::cout << std::setprecision(4) << 123.456 << '\n';
std::cout << std::setprecision(5) << 123.456 << '\n';
std::cout << std::setprecision(6) << 123.456 << '\n';
std::cout << std::setprecision(7) << 123.456 << '\n';
產生結果:
123.456
123.4560
123.45600
123.456000
123.4560000
1.235e + 002
1.2346e + 002
1.23456e + 002
1.234560e + 002
1.2345600e + 002
如果既不使用固定也不科學,精度確定應顯示多少有效數字。同樣,如果精度小於有效位數,則數字將被舍入。
std::cout << std::setprecision(3) << 123.456 << '\n';
std::cout << std::setprecision(4) << 123.456 << '\n';
std::cout << std::setprecision(5) << 123.456 << '\n';
std::cout << std::setprecision(6) << 123.456 << '\n';
std::cout << std::setprecision(7) << 123.456 << '\n';
產生以下結果:
123
123.5
123.46
123.456
123.456
使用showpoint操縱器或標誌,可以使流寫入小數點並尾隨零。
std::cout << std::showpoint << '\n';
std::cout << std::setprecision(3) << 123.456 << '\n';
std::cout << std::setprecision(4) << 123.456 << '\n';
std::cout << std::setprecision(5) << 123.456 << '\n';
std::cout << std::setprecision(6) << 123.456 << '\n';
std::cout << std::setprecision(7) << 123.456 << '\n';
產生以下結果:
123。
123.5
123.46
123.456
123.4560
這是一個包含更多示例的彙總表:
寬度,填充字元和對齊方式
通常,當您列印數字時,會列印數字而不考慮它們周圍的空間。但是,可以向左或向右對齊數字的列印。為此,我們必須首先定義一個欄位寬度,它定義一個值將具有的輸出空間的數量。如果列印的實際數字小於欄位寬度,則將左對齊或右對齊(如指定的那樣)。如果實際數字大於欄位寬度,則不會被截斷 - 它將溢位欄位。
Group | Flag | 含義 |
---|---|---|
adjustfield | internal | 左對齊數字的符號,並對該值進行右對齊 |
adjustfield | left | 以左對齊符號和值 |
adjustfield | right | 右對齊符號和值(預設) |
Manipulator | 含義 |
---|---|
internal | 左對齊數字的符號,並對該值進行右對齊 |
left | 左對齊符號和值 |
right | 右對齊符號和值(預設) |
setfill(char) | 將引數設定為填充字元(在iomanip.h中定義) |
setw(int) | 將輸入和輸出的欄位寬度設定為引數(在iomanip.h中定義) |
成員函式 | 含義 |
---|---|
fill() | 返回當前填充字元 |
fill(char) | 設定填充字元並返回舊填充字元 |
width() | 返回當前欄位寬度 |
width(int) | 設定當前欄位寬度並返回舊欄位寬度 |
為了使用任何這些格式化程式,我們首先必須設定欄位寬度。這可以通過width(int)成員函式或setw()操縱器來完成。請注意,右對齊是預設值。
std::cout << -12345 << '\n'; //列印預設值,沒有欄位寬度
std::cout << std::setw(10) << -12345 << '\n'; // 列印預設欄位寬度
std::cout << std::setw(10) << left << -12345 << '\n'; // 列印左對齊
std::cout << std::setw(10) << right << -12345 << '\n'; // 列印右對齊
std::cout << std::setw(10) << internal << -12345 << '\n'; // 列印內部合理
這會產生結果:
-12345
-12345
-12345
-12345
- 12345
需要注意的一點是setw()和width()隻影響下一個輸出語句。它們不像其他標誌/操縱器那樣持久。
現在,讓我們設定一個填充字元並執行相同的示例:
std::cout.fill('*');
std::cout << -12345 << '\n'; // print default value with no field width
std::cout << std::setw(10) << -12345 << '\n'; // print default with field width
std::cout << std::setw(10) << left << -12345 << '\n'; // print left justified
std::cout << std::setw(10) << right << -12345 << '\n'; // print right justified
std::cout << std::setw(10) << internal << -12345 << '\n'; // print internally justified
這會產生輸出:
-12345
**** - 12345
-12345 ****
**** - 12345
- **** 12345
請注意,欄位中的所有空格都填充了填充字元。
ostream類和iostream庫包含其他可能有用的輸出函式,標誌和操作符,具體取決於您需要執行的操作。與istream類一樣,這些主題更適合專注於標準庫的教程或書籍(例如Nicolai M. Josuttis出版的優秀書籍“The C ++ Standard Template Library”)。