深入解析C++输入输出运算符重载
2012-05-07 22:45
351 查看
其实算不上什么深入解析,只不过最近看CArchive类的实现,其中一些写法完全颠覆了我对输入输出运算符重载的一些理解,所以在这里mark一下。
我们以输出运算符为例。首先输出运算符重载的一般形式是
ostream是c++流输出的类,至于友元,只记得说输入输出运算符必须用友元重载,因为ostream是受保护的。今天看CArchive类实现的时候,里面有如下的定义
于是才发觉ostream并不是必需的,换句话说,从语法上讲,ostream的位置放什么类都可以,只不过语义上要行得通。而友元的重载从语法上讲也不是必须的,比如可以依然用成员函数重载,函数定义变成如下的格式
使用的时候只能用object>>cout(或者cout>>object这就太别扭了)形式了,并且不可能连续使用了(比如obj1>>obj2>>cout),这违背了C++规范,但是语法上是的过得去的。
举一个简单而诡异的例子(原谅我这里诡异的代码风格,只是个演示)
绕了两个圈圈,只是为了说明输入输出运算符语法上讲完全可以像普通运算符一样重载,但是语义上看输出运算符<<里,ostream只能做左值,而ostream不能让你去添加一个成员函数,所以只能用友元重载,输入运算符里,istream也只能做左值,因而同样只能用友元重载。
最后,需要注意两个问题。首先是为什么一定要返回一个ostream&或者类似的引用?我们可以从这个例子来想
编译器求值的时候按优先级从左向右进行,cout<<obj1相当于调用函数[1],结果为ostream的引用才能继续进行右边的<<obj2,这也解释了为什么如下语句是编译不过去的(CArchive里没有对ostream对象的输出运算符重载,因而ar<<obj1返回CArchive&引用之后下一步就报错了)。
其次,函数参数里的ostream& o不能加const,因为你实现里几乎一定会写o<<….,这里相当于调用ostream对应的重载函数修改ostream,因而编译的时候会报错。
我们以输出运算符为例。首先输出运算符重载的一般形式是
friend ostream& operator<<(ostream& o,const ClassName& c);[1]
ostream是c++流输出的类,至于友元,只记得说输入输出运算符必须用友元重载,因为ostream是受保护的。今天看CArchive类实现的时候,里面有如下的定义
friend CArchive& AFXAPI operator>>(CArchive& ar, CObject*& pOb);
于是才发觉ostream并不是必需的,换句话说,从语法上讲,ostream的位置放什么类都可以,只不过语义上要行得通。而友元的重载从语法上讲也不是必须的,比如可以依然用成员函数重载,函数定义变成如下的格式
ostream& operator>>(ostream& o);
使用的时候只能用object>>cout(或者cout>>object这就太别扭了)形式了,并且不可能连续使用了(比如obj1>>obj2>>cout),这违背了C++规范,但是语法上是的过得去的。
举一个简单而诡异的例子(原谅我这里诡异的代码风格,只是个演示)
#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&引用之后下一步就报错了)。
CArchive ar(&file,CArchive::store); ar<<obj1<<endl;
其次,函数参数里的ostream& o不能加const,因为你实现里几乎一定会写o<<….,这里相当于调用ostream对应的重载函数修改ostream,因而编译的时候会报错。
相关文章推荐
- 深入解析C++输入输出运算符重载
- 深入解析C++输入输出运算符重载
- 【C++ STL】深入解析神秘的 --- 仿函数
- 深入解析C++中的指针数组与指向指针的指针
- 玩转Google开源C++单元测试框架Google Test系列(gtest)之七 - 深入解析gtest
- virtualStudio C++ 深入解析(一)
- C++学习之深入理解虚函数--虚函数表解析
- C++ 构造函数 析构函数 拷贝构造函数 运算符重载解析。
- C++ 虚函数表解析(原理讲述不甚深入且不太权威)
- C++输入输出运算符重载(“>>”“<<”)
- C++直接初始化与复制初始化的区别深入解析
- C++ 类的静态成员深入解析
- c++输入输出重载,赋值,加法运算符重载
- c/c++中变量的声明和定义深入解析
- C++ 输入输出运算符重载 感想
- 玩转Google开源C++单元测试框架Google Test系列(gtest)之七 - 深入解析gtest
- 深入解析C++虚函数机制
- C++ Const深入解析
- C++实现输入输出运算符重载、友元函数和成员函数实现复数类Complex
- 『C/C++』[C# 基础知识系列]专题一:深入解析委托——C#中为什么要引入委托