首页 > C/C++ > 重载流操作符的函数定义 -- 一个小问题所想到的

重载流操作符的函数定义 -- 一个小问题所想到的

2011年10月8日 发表评论 阅读评论
文章作者:Yx.Ac   文章来源:勇幸|Thinking (http://www.ahathinking.com)   转载请注明,谢谢合作。

 

以前助教班的学生昨天问了一个小问题: 重载输出流操作符的定义为什么一定是如下格式:

ostream & operator << (ostream & output, const ClassType & object)
{
	output << ...
	...
	return output;
}

他说以前遇到这种格式“复杂”的东西直接看参考书怎么写的,今天突然觉得这个为什么这样写啊,写成其他的形式不行么?记得我刚学C++的时候也犯过类似抄参考书的毛病,后来慢慢才理解了。针对重载输出流操作符有如下问题:

  1. 返回类型为什么是引用?
  2. 第一个参数为什么用引用?
  3. 第二个参数为什么又是const引用?

一个函数的定义,从返回类型到形参列表,我们都要有清晰的认识和理解,才能明白应该怎样编写这个函数。

  1. 返回引用是为了使得返回结果为左值,相当于一个独立对象的作用,使我们可以做连续输出的操作,例如
     cout << object1 << object2 <<endl; 

    注意:返回引用要慎用,尤其是不能返回局部变量的引用,一般返回引用是针对当前对象返回 *this 或者返回const 类型的引用。

  2. 第一个参数之所以为引用,首先是避免了IO对象的复制,注意:这里不是刻意避免IO对象的复制,而是IO对象不可复制或赋值,所以这里必须用引用类型,不能传递流类型。由此我们应该知道,既然IO对象不支持复制或赋值,则一方面流对象不能存储在vector或其它容器中(只有支持复制的类型才可以存储vector等容器中);另一方面,形参或返回类型都不能为流类型(因为涉及复制),如果要传递或返回IO对象,则必须传递指向该流对象的指针或引用。此外,可能你会注意,为什么第二个参数为const类型,那第一个参数为什么不是const呢?ostream之所以为非const类型,很明显,写入流会改变流的状态,所以使用非const
  3. 第二个形参为const类型的引用,关于这样形参的好处,在博文“美妙的const”中有详细阐述。首先对于要输出的类类型,避免了对象的复制;其次,一般输出一个对象是不应该改变该对象的,故为const;再者,const引用可以使得传递参数更为灵活,例如,这样定义,我们就可以使用同一个定义来传递输出const和非const对象。关于const与非const对象的问题,参见博文美妙的const.
  4. 说到这里,顺便提一下重载输入流操作符,在输入流操作符函数定义中,第二个参数则必须为非const,因为输入流要改变该对象。

综上,这里面的每个细节都是必须的,不能更改。

值得一提的是,重载流操作符函数必须为类的非成员函数。原因是,如果设定为成员函数,则做操作数必然为该类的类对象,用法就变成了

object << cout

这显然与我们所要的相悖。说到这里就顺便说一下为类设计重载操作符时候应该将其设置为类的成员函数还是非成员函数,下面是我的总结,仅供参考:

  • 必须为成员函数5个:赋值(=),下标符([ ]),调用符(( )),成员访问箭头符(->),“转换函数”。前两个比较常用,调用符重载即函数对象,箭头符不太常见,指针类型类会用到;转换函数则是用在“从”类类型到内置类型的转换时用到(标准转换为内置类型的转换,类类型的转换则分为“从”类类型的转换和“到”类类型的转换)
  • 建议为成员函数4个:复合赋值操作符,自增,自减,解引用;这几个操作符是与类类型紧密相连的或改变对象状态的操作符。
  • 必须为非成员函数1种:流操作符(输入、输出)
  • 建议为非成员函数4种:等等操作符,算术操作符,关系操作符,位操作符

到这里吧,一个流操作符函数唠叨了这么多,都是基础,类似上面这些基础知识,在《C++ primer》中都有涉及,而且分析的很好。

下面说一点自己的感受吧,在学习一个新东西的时候,我们不能局限课本,有时间还是看看那些经典的书籍,可以少走很多弯路,我体会最深的一点就是当时学习C++的“拷贝构造函数”、“析构函数”、“重载赋值运算符”时纠结了很长一段时间,记得那时往往析构的时候编译器总是弹框,还有什么深拷贝浅拷贝的问题,后来写了很多程序废了好大劲才觉得有点眉目,总结出来是如果类中有指针成员,就要注意上面的那些函数问题,是否需要定义自己的拷贝构造和重载赋值运算符等等。

后来看了《C++ primer》,当看到“复制控制”那一章时,记得当时真有种捶胸顿足的感觉,明明前人都总结的“经验三法则”在那里摆着,我却不知道,如果早点看就不至于走那么多弯路了,而且自己总结出来的总有点山寨的感觉,所以经典很重要,我们必须要学会“站在巨人肩膀上”,这样也可以提高效率,加快进步。