1. 程式人生 > >C++基礎教程面向物件(學習筆記(103))

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”)。