其实算不上什么深刻解析,只不过最近看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,于是编译的时候会报错。编译