ostream operator <<
這一篇要介紹的是,到底cout是什麼樣的物件呢?它是如何產生出來的。
作者說明的版本是VC,並以MSDN中的資料做輔助。
在前一篇文章介紹的是ostream.h內的內容,主要是因為先不讓讀者模糊,先讓讀者建立起觀念,而在此篇文章
介紹的是標題檔ostream的內容,它使用到模板(template),所以這篇文章將重點放在模板的具現化。
基本上ostream.hostream,不是不一樣的東西,因為C++標準制定與版本的問題,不需要太在意。
在ostream.h的觀念可以衍用在ostream,只是需多加注意到模板(template)的問題。
在介紹之前,先介紹兩個VC中的修飾詞__cdecl_CRTIMP,可以不在意它的存在,因為那並不是重點所在:
__cdecl是一個calling convertion,它支援函數有可變個數的參數(variable number of arguments),像printf(...)
它的參數個數可以不定,不定的參數,而參數推入堆疊的方式是由右而左。這不屬於 C/C++的一部份。
詳細參考這裡:Calling Conventions
_CRTIMP是微軟所定義出來的MACO,允許選擇需要的程式庫版本(LIB or DLL),因為這不是 C/C++的一部份,所
以本身並沒有多大的興趣,可以找有關VC這方面的資料來研究。
接下來程式內出現_CRTIMP__cdecl這個詞,我都會將它拿掉,只會出現與Standard C/C++有關程式
相信學C++的人,最常引用的標題檔應該是iostream,如果打開來的話,會看到有這一行:	
	extern ostream cout;
cout的資料型態是ostream,那ostream是什麼呢?(查至MSDN)	
	typedef basic_ostream<char, char_traits<char> > ostream;
basic_ostream是什麼呢?(查至標題檔ostream)	
template<class _E, class _Tr = char_traits<_E> >
	class basic_ostream : virtual public basic_ios<_E, _Tr> {...}
basic_stream是一個class template(類別範本;類別模板),而模板的參數列(template parameter list)中有兩個
型別參數class _Eclass_Tr = char_traits<_E>
作者查了一下:
引至《C++ 標準程式庫 第13章 以Stream Classes 完成輸入和輸出 》
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
class _Ebasic_ostream 所使用的字元型別
class _Tr class _E 的特性類別(traits class)

在特性類別中,end-of-file(表示資料輸入結束符號)值和複製/移動字元序列的各個指令,都屬於特性(traits)的
一部份。字元型別的特性(traits)和字元型別本身通常密不可分,因此定義一個template class並針對特定型別
實施特化也就合情合理。針對字元型別_E,特性類別class _Tr預設為char_traits<_E>
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
class _E可以把它看成是串流(stream)中每個的字元(或元素)型別,一般若無關連到國際化的議題時,字元型別
char已經足夠解決問題了。有了字元型別之後,要依照字元型別的型態去呼叫相對應的處理函式或相關操作,而
char_traits類似這個作用,字元特性類別處理的動作像是判斷字元是否相等、傳回字串長度、指派動作...等等。
這是C++中比較高段的運用,作者沒有深入這方面的研究,但概念有的話,才不會不知道在做什麼。基本上作者
的學習的方式是有機會接觸到或碰到問題時,藉著與別人的討論之中得到觀念並閱讀相關的書籍,從問答中學習。
作者並不喜歡看書。
到此若對前面的介紹不清楚,沒關係,接下來介紹的,會將它們連結在一起,現在要開始從標題檔ostream中,
operator <<的整個動作情形,建議在閱讀之前,可以把有介紹class template的書籍拿來出當作參考。
先來看段程式:

	#include <iostream>
	using namespace std;
	int main()
	{
		char *ch="James";

		cout<<ch;
		return 0;
	}
前一篇文章說到cout型態為char *的資料時,會呼叫const char *,有沒有真得試過看看呢?
沒試沒有關係,現在試試看,程式寫完之後,按F11,會按到黃色箭頭跳到標題檔ostream這裡:
template<class _E, class _Tr> inline
	basic_ostream<_E, _Tr>&  operator<<(basic_ostream<_E, _Tr>& _O, const _E *_X)
這是什麼東東呀!operator<<本身你可以把寫看成是一個函數,回傳值basic_ostream<_E, _Tr>&,參數
(basic_ostream<_E, _Tr>& _O, const _E *_X),而這個函數是函數模板(function template),可以依照
不同的模板的參數列(template parameter list)具現化(instantiated)出不同的版本的operatpr<<,而不必只因為
參數型態的重覆撰寫。當使用到模板時(template),參數_E_Tr將被取代成當時引數的型態。過程如下:
當執行到這一行 cout<<ch;
其實它跟以下是一樣的:
	operator << ( cout , ch );
cout的型態是ostream,而ostreambasic_ostream<char, char_traits<char> > 
因為chchar *,所以呼叫此以下函式模板,若是int,float...etc.則並不是呼叫此函式模板,而是呼叫該型態是
operator<<,稍後會介紹。
template<class _E, class _Tr> inline
	basic_ostream<_E, _Tr>&  operator<<(basic_ostream<_E, _Tr>& _O, const _E *_X)
operator << ( cout , ch );與上互相對應,參數列中的basic_ostream<_E, _Tr>& _O 所對應到的是 cout
cout型態是basic_ostream<char, char_traits<char> > ,所以_E_Trderive出為:
_E = char
_Tr = char_traits<char>
函式模式(function template)變成:
inline basic_ostream<char , char_traits<char> >& 
 	 operator<<(basic_ostream<char , char_traits<char> >& _O, const char *_X)
basic_ostream<char , char_traits<char> >之前說過,就是ostream,所以可以簡化為:
inline ostream& operator<<(ostream& _O, const char *_X)
註:請記得兩個>之間是有空格的,若沒有的話會被編譯器誤認為>>(右移運算子)
那是不是跟作者之前所說的,當使用char *時,會呼與const char *型態的operator<< 
那如果改成cout<<36呢?會怎麼樣,試試看:
一樣按F11,直到跳到標題檔ostream
	_Myt& operator<<(int _X){...}
什麼是_Myt呢?在Debug的視窗中將捲軸往上拉,應該會看到:
	template<class _E, class _Tr = char_traits<_E> >
	class basic_ostream : virtual public basic_ios<_E, _Tr> {
public:
	typedef basic_ostream<_E, _Tr> _Myt;
	typedef basic_ios<_E, _Tr> _Myios;
	...
	...
O!原來_Myt就是basic_ostream<_E , _Tr>,為了便利所以用了typedef來代替那麼長串的型態。那怎麼知道
_E_Tr是什麼呢?一樣的方法:
	cout<<36;
與下列是一樣的:
	cout.operator<<(36);
cout的型態是ostream,而ostreambasic_ostream<char, char_traits<char> > 
(有沒有注意到,因為operator<<第二個引數型態的不同,會呼叫不同參數型態的operator<<)
所以同樣的方式,最後能夠derive出:
	ostream & operator << (int _X){...}
介紹到此,應該能夠瞭解coutoperator<<大概了!自己在試試看囉!!!
 
回目錄
Written By James On 2004/02/08 

Hosted by www.Geocities.ws

1