cout

計算機編程術語

cout 用於在計算機屏幕上顯示信息,是C++中iostream 類型的對象,C++的輸出是用“流”(stream)的方式實現的,流運算符的定義等信息是存放在C++的輸入輸出流庫中的,因此如果在程序中使用cout和流運算符,就必須使用預處理命令把頭文件stream包含到本文件中,即 <iostream > 庫,該庫定義的名字都在命名空間 std 中,所以 cout 全稱是 std::cout 。

簡介


輸入和輸出並不是C++語言中的正式組成成分。C和C++本身都沒有為輸入和輸出提供專門的語句結構。輸入輸出不是由C++本身定義的,而是在編譯系統提供的I/O庫中定義的。
C++的輸出和輸入是用“流”(stream)的方式實現的。圖示通過流進行輸入輸出的過程。
有關流對象cin、cout和流運算符的定義等信息是存放在C++的輸入輸出流庫中的,因此如果在程序中使用cin、cout和流運算符,就必須使用預處理命令把頭文件stream包含到本文件中: #include 儘管cin和cout不是C++本身提供的語句,但是在不致混淆的情況下,為了敘述方便,常常把由cin和流提取運算符“>>”實現輸入的語句稱為輸入語句或cin語句,把由cout和流插入運算符“<<”實現輸出的語句稱為輸出語句或cout語句。根據C++的語法,凡是能實現某種操作而且最後以分號結束的都是語句。
cout
cout

基本操作


cout語句的一般格式為: cout<<表達式1<<表達式2<<……<<表達式n;
在定義流對象時,系統會在內存中開闢一段緩衝區,用來暫存輸入輸出流的數據。在執行cout語句時,先把插入的數據順序存放在輸出緩衝區中,直到輸出緩衝區滿或遇到cout語句中的endl(或'\n',ends,flush)為止,此時將緩衝區中已有的數據一起輸出,並清空緩衝區。輸出流中的數據在系統默認的設備(一般為顯示器)輸出。
一個cout語句可以分寫成若干行。如:
cout<<"This is a simple C++ program."<
可以寫成
cout<<"This is " //注意行末尾無分號
<<"a C++ "
<<"program."
<
也可寫成多個cout語句,即
cout<<"This is "; //語句末尾有分號
cout <<"a C++ ";
cout <<"program.";
cout<
以上3種情況的輸出均為:
This is a simple C++ program.
注意:
不能用一個插入運算符“<<”插入多個輸出項,如:
cout<
cout<
在用cout輸出時,用戶不必通知計算機按何種類型輸出,系統會自動判別輸出數據的類型,使輸出的數據按相應的類型輸出。如已定義a為int型,b為float型,c為char型,則:
cout<
會以下面的形式輸出: 4 345.789 a

使用範例


案例分析


請看HelloWorld!的等效版本:
cout是一個ostream類的對象,它有一個成員運算符函數operator<<,每次調用的時候就會向輸出設備(一般就是屏幕啦)輸出數據。
問題:為什麼函數operator<<能夠接受不同類型的數據,如整型、浮點型、字元串甚至指針?
運算符函數與一般函數基本無異,可以任意重載。標準庫的設計者們早已經為用戶定製了iostream::operator<<對於各種C++基本數據類型的重載版本,這才使得我們這些初學者們一上來就享受到cout<<"Hello,World!"<<endl;。
問題:為什麼可以連續寫多個?
請見如下的定義:
注意前面的ostream&表示返回對象的引用,也就是可以繼續cout了。
對於cin,則是istream流類的對象,其重載了>>運算符,用法與cout大致相同

技巧應用


把設計的cout對象命名的myout,myout對象所屬的類為MyOutstream。要做的就是為MyOutstream類重載一系列不同類型的operator<<運算符函數,這裡僅實現了對整型(int)與字元串型(char*)的重載。為了表示與iostream斷絕關係,不再用頭文件iostream。
定義的myout已經初具形態,可以工作了。程序中的註釋指出兩處要特別注意的:即是operator<<函數執行完畢之後,返回一個它本身的引用,輸出已經完成,為何還要多此一舉?
還記得那個有點奇異的cout.operator<<("Hello,World!").operator<<(endl)么?它能實現意味著我們可以連著書寫
而不是
為何它可以這樣連起來寫?
分析一下:按執行順序,系統首先調用cout.operator<<("Hello,World!"),然後cout.operator<<會返回它本身,就是說在函數的最後一行會出現類似於return *this這樣的語句,因此cout.operator<<("Hello,World!")的調用結果就返回了cout,接著它後面又緊跟著.operator<<(endl),這相當於cout.operator<<(endl)——於是又會進行下一個輸出,如果往下還有很多<<算符。

控制符


要使用下面的控制符,需要在相應的源文件中包含頭文件“iomanip”,也就是添加如下代碼:
控制符描 述
dec置基數為10,後由十進位輸出(系統默認形式)
hex置基數為16,後由十六進位輸出
oct置基數為8,後由八進位輸出
setfill(c)設填充字元為c
setprecision(n)設置實數的精度為n位
setw(n)設域寬為n個字元
setiosflags(ios::fixed)固定的浮點顯示
setiosflags(ios::scientific)指數表示
setiosflags(ios::left)左對齊
setiosflags(ios::right)右對齊
setiosflags(ios::skipws)忽略前導空白
setiosflags(ios::uppercase)16進位數大寫輸出
setiosflags(ios::lowercase)16進位數小寫輸出
其中:setw設置域寬,使用一次就得設置一次。其他的函數,設置一次永久有效。

有關信息


1 cout的類型是 iostream
2 ostream使用了單例模式,
保護的構造函數,不能在類外創建另一個對象(用 ostream os 測試)
拷貝構造私有,不能通過已有對象,構造新對象(用 ostream os(cout) 測試)
拷貝賦值私有,(用 cout=cout 測試)
3 cout在命名空間std中,使用前需要using namespace std,或者std::cout
4 可以使用引用,或指針指向這個對象,意思想說,想用ostream 做一個函數的形式參數,就必須使用引用或指針。因為實參肯定是cout,且只能有這一個對象。
5 cout<<對象;對象的類型用OO表示,如想用cout列印一個對象,即cout<<對象,可使用如下程序

運算符重載


用法:把成員函數/友元函數的名字改為 operator運算符 就行了。

內容


cout
C++編程語言互換流中的標準輸出流,需要iostream.h支持。讀為 c out
使用範例:
#include iostream.h
int main()
{
int a;
cout請輸入一個數字,按回車結束endl;
cin a;
coutaendl;
return 0;
}
用戶輸入的數字由cin保存於變數a中,並通過cout輸出。
#include
using namespace std;
int main()
{
coutHello,World!endl;
return0;
}
由於以前學過C,所以這段代碼的其它部分在我看來都還算“正常”,然而cout卻很獨特:既不是函數,似乎也不是C++特別規定出來的像if,for一類有特殊語法的“語句”。由於只是初步介紹,所以那本書只是簡單的說cout是C++中的“標準輸入輸出流”對象……這於我而言實在是一個很深奧的術語。這還沒完,之後又遇見了cin……因為不知底細,從此使用它們的時候都誠惶誠恐,幾欲逃回C時代那簡明的printf(),畢竟好歹我可以說:我在調用的是一個函數。那有著一長串、的玩意,究竟算怎麼回事呢?我一直想把它們當作關鍵字,可偏偏不是,而且居然是用C++語言“做”出來的,呵!但printf()用多了就開始有人好心地批判我的程序“C語言痕迹過重”……
後來隨著學習的深入,總算大概明白了cout/cin/cerr/...的鬼把戲:那些東東不過是變著法兒“哄人”,其實說到底還是函數調用,不過這函數有些特殊,用的是運算符重載,確切地說(以下還是以cout為例)是重載了“”運算符。我們現在就讓它現出函數的本來面目,請看HelloWorld!的等效版本:
#include
using namespace std;
int main()
{
cout.operator(Hello,World!);
cout.operator(endl);
return 0;
}
編譯運行,結果與經典版無二。上面程序應該更容易理解了:cout是一個iostream類的對象,它有一個成員運算符函數operator,每次調用的時候就會向輸出設備(一般就是屏幕啦)輸出東東。嗯,這裡有一個問題:為什麼函數operator能夠接受不同類型的數據,如整型、浮點型、字元串甚至指針,等等呢?
我想你現在已經猜到了,沒錯,就是用運算符重載。運算符函數與一般函數基本無異,可以任意重載。標準庫的設計者們早已經為我們定製了iostream::operator對於各種C++基本數據類型的重載版本,這才使得我們這些初學者們一上來就享受到coutHello,World!endl;
cout.operator(Hello,World!).operator(endl);
才算“強等效”。究竟可不可以這樣寫?向編譯器確認一下……OK,NoProblem!
嗯,我們已經基本上看出了cout的實質,現在不妨動動手,自己來實現一個cout的簡化版(Lite),為了區分,我們把我們設計的cout對象命名的myout,myout對象所屬的類為MyOutstream。我們要做的就是為MyOutstream類重載一系列不同類型的operator運算符函數,簡單起見,這裡我們僅實現了對整型(int)與字元串型(char*)的重載。為了表示與iostream斷絕關係,我們不再用頭文件iostream,而使用古老的stdio中的printf函數進行輸出,程序很簡單,包括完整的main函數,均列如下:
#include//在C和一些古老的C++中是stdio.h,新標準為了使標準庫
//的頭文件與用戶頭文件區別開,均推薦使用不用擴展名
//的版本,對於原有C庫,不用擴展名時頭文件名前面要加c
class MyOutstream
{
public:
const MyOutstream operator(int value)const;//對整型變數的重載
const MyOutstream operator(char* str)const;//對字元串型的重載
};
const MyOutstream MyOutstream::operator(int value)const
{
printf(%d,value);
return *this;//注意這個返回……
}
const MyOutstream MyOutstream::operator(char*str)const
{
printf(%s,str);
return *this;//同樣,這裡也留意一下……
}
MyOutstream myout;//隨時隨地為我們服務的全局對象myout
int main()
{
int a=2003;
char* myStr=Hello,World!;
myoutmyStr\n;
return 0;
}
我們定義的myout已經初具形態,可以為我們工作了。程序中的註釋指出兩處要我們特別注意的:即是operator函數執行完畢之後,總是返回一個它本身的引用,輸出已經完成,為何還要多此一舉?
還記得那個有點奇異的cout.operator(Hello,World!).operator(endl)么?它能實現意味著我們可以連著書寫
coutHello,World!endl;
而不是
coutHello,World!;
coutendl;
為何它可以這樣連起來寫?我們分析一下:按執行順序,系統首先調用cout.operator(Hello,World!),然後呢?然後cout.operator會返回它本身,就是說在函數的最後一行會出現類似於return *this這樣的語句,因此cout.operator(Hello,World!)的調用結果就返回了cout,接著它後面又緊跟著.operator(endl),這相當於cout.operator(endl)——於是又會進行下一個輸出,如果往下還有很多算符,調用就會一直進行……哇噢,是不是很聰明?現在你明白我們的MyOutstream::operator最後一行的奧妙了吧!
再注意一下main函數中最激動人心的那一行:
myout\n
我們知道,最後出現的\n可以實現一個換行,不過我們在用C++時教程中總是有意無意地讓我們使用endl,兩者看上去似乎一樣——究竟其中有什麼玄妙?查書,書上說endl是一個操縱符(manipulator),它不但實現了換行操作,而且還對輸出緩衝區進行刷新。什麼意思呢?原來在執行輸出操作之後,數據並非立刻傳到輸出設備,而是先進入一個緩衝區,當適宜的時機(如設備空閑)后再由緩衝區傳入,也可以通過操縱符flush,ends,或unitbuf進行強制刷新:
coutHello,World!Flush the screen now!!!flush;
這樣當程序執行到operator(flush)之前,有可能前面的字元串數據還在緩衝區中而不是顯示在屏幕上,但執行operator(flush)之後,程序會強制把緩衝區的數據全部搬運到輸出設備並將其清空。而操縱符endl相當於\nfush;
不過可能在屏幕上顯示是手動刷新與否區別看來都不大。但對於文件等輸出對象就不大一樣了:過於頻繁的刷新意味著老是寫盤,會影響速度。因此通常是寫入一定的位元組數后再刷新,如何操作?靠的就是這些操縱符。
  • 目錄