其實算不上什麼深刻解析,只不過最近看CArchive類的實現,其中一些寫法徹底顛覆了我對輸入輸出運算符重載的一些理解,因此在這裏mark一下。ios
咱們以輸出運算符爲例。首先輸出運算符重載的通常形式是c++
friend ostream& operator<<(ostream& o,const ClassName& c);[1]
ostream是c++流輸出的類,至於友元,只記得說輸入輸出運算符必須用友元重載,由於ostream是受保護的。今天看CArchive類實現的時候,裏面有以下的定義函數
friend CArchive& AFXAPI operator>>(CArchive& ar, CObject*& pOb);
因而才發覺ostream並非必需的,換句話說,從語法上講,ostream的位置放什麼類均可以,只不過語義上要行得通。而友元的重載從語法上講也不是必須的,好比能夠依然用成員函數重載,函數定義變成以下的格式this
ostream& operator>>(ostream& o);
使用的時候只能用object>>cout(或者cout>>object這就太彆扭了)形式了,而且不可能連續使用了(好比obj1>>obj2>>cout),這違背了C++規範,可是語法上是的過得去的。spa
舉一個簡單而詭異的例子(原諒我這裏詭異的代碼風格,只是個演示)code
#include "stdafx.h"#include <iostream>using namespace std;class output{public: output& operator<<(int i); };output& output::operator<<( int i ) { cout<<i; return *this; }class CComplex{ int x; int y;public: CComplex(int _x,int _y):x(_x),y(_y){} output& operator>>(output& o); };output& CComplex::operator>>( output& o ) { o<<x<<y; return o; }int _tmain(int argc, _TCHAR* argv[]) { CComplex c(1,2); c>>output(); }
繞了兩個圈圈,只是爲了說明輸入輸出運算符語法上講徹底能夠像普通運算符同樣重載,可是語義上看輸出運算符<<裏,ostream只能作左值,而ostream不能讓你去添加一個成員函數,因此只能用友元重載,輸入運算符裏,istream也只能作左值,於是一樣只能用友元重載。對象
最後,須要注意兩個問題。首先是爲何必定要返回一個ostream&或者相似的引用?咱們能夠從這個例子來想編譯器
cout<<obj1<<obj2<<endl;
編譯器求值的時候按優先級從左向右進行,cout<<obj1至關於調用函數[1],結果爲ostream的引用才能繼續進行右邊的<<obj2,這也解釋了爲何以下語句是編譯不過去的(CArchive裏沒有對ostream對象的輸出運算符重載,於是ar<<obj1返回CArchive&引用以後下一步就報錯了)。io
CArchive ar(&file,CArchive::store);ar<<obj1<<endl;
其次,函數參數裏的ostream& o不能加const,由於你實現裏幾乎必定會寫o<<….,這裏至關於調用ostream對應的重載函數修改ostream,於是編譯的時候會報錯。編譯