C++中,我們可以重載輸入輸出流操作符<<與>>來自定義其輸入輸出功能。
class Foo { public: Foo() :high(0), wide(0){} Foo(int a, int b) :high(a), wide(b){} Foo & operator++();//前置 const Foo operator++(int);//后置調用前置 friend const ostream& operator<< (const ostream&,const Foo&); //這樣寫 流對象之前加const常量限制符,會報錯 private: int high; int wide; }; const ostream& operator<< (const ostream& os, const Foo& foo) { os << foo.high << " " << foo.wide; return os; }
上面的寫法 在流對象之前使用 const ,編譯器會報錯,報錯提示如下:
錯誤提示原因是 輸入流對象 沒有匹配的 常量類型 輸出。說白了就是 輸出流操作 不能在輸出 一個數據流而其本身沒有任何變化。(如果理解不了這句話,可以先跳過,往后繼續看,相信看完之后再來看這句話,就能理解了)
下面來試試去掉const常量修飾符之后的結果:
class Foo { public: Foo() :high(0), wide(0){} Foo(int a, int b) :high(a), wide(b){} Foo & operator++();//前置 const Foo operator++(int);//后置調用前置 friend ostream& operator<< (ostream&,const Foo&); //這是去掉const常量修飾符,正確的做法 private: int high; int wide; }; ostream& operator<< (ostream& os, const Foo& foo) { os << foo.high << " " << foo.wide; return os; }
編譯通過,沒有報錯。
為什么加上const 修飾符之后,就是錯誤的呢?const 是用來修飾不會改變的 對象或變量狀態的常量修飾符。而此處不能在重載的流對象之前加 const 說明 Foo類的友元函數 輸出流對象 之后改變了流對象本身的狀態。
C++ primer 對此的描述是“讀寫IO對象會改變其狀態,返回的引用不能是const“。
那么一個流對象,使用之后,其狀態為什么被改變了呢?
我們先來想一下我們處理一個文本文件的場景:先打開一個文本文件,獲得其句柄,通過該句柄可以對其讀寫操作(注意此處的讀寫操作,很像我們的流操作。其實C++的文件操作,標准化就是通過重載<<與>>進行流讀寫的)。文件讀寫通過兩個文件指針,一個讀指針,一個寫指針,每次進行讀或寫操作,讀寫指針就會自動往后移動。注意這里,讀寫指針自動移動。這里就已經改變了文件的流對象 的狀態。
同理,我們的屏幕輸出流對象和鍵盤輸入流對象,也有這么類似的一對自動移動的讀寫指針,每次進行流操作時,例如在屏幕打印一個字符,屏幕輸出流對象的位置指針就會向后移動一個單位。這里就改變了流對象的狀態。
下面引用一位網友對此形象的描述:河里的水流雖然看起來沒有變化,但是有水流過,肯定有東西發生了變化(河床發生了侵蝕,沙子發生了沉積)。