C++运算符重载,+-*/的重载,返回值为什么是对象而不是对象的引用?而流操作符<< 和 >> 却返回的是引用?
原因是:
+,-,*等返回不了引用,比如+运算符,可以如下重载(为了简单,假设A 只有int x;int y)
A operator+(A a,A b) {A sum; sum.x=a.x+b.x; sum.y=a.y+b.y; return sum; }
分析不能用引用的原因: 函数传入了两个参数a,b,并且+只能传入两个参数(c++不允许自己创造运算符),这样就限定了和sum不能作为参数传入,所以sum只能是一个函数里的临时变量,但是临时变量在函数结束时是要销毁的,那么函数调用玩,sum就没有了, 如果返回引用,引用源都已经没有了,还怎么引用,引用哪里的东西呢??
所以不能引用。
<<,>>可以返回引用,而且不返回引用也是编译不过的,貌似是c++的要求。可以不用引用试一试,有的编译器会出来一个ios_base.h文件,就是想告诉你用引用。
返回引用也是可以解释的。 比如还是上面的A类型,如下
ostream& operator<<(ostream& out, const A& a) { out<<A.x<<' '<<A.y<<endl; retrun out;}
能返回引用,首先是因为out是作为参数传入的,不是函数的临时变量,函数结束时它仍然存在,这样就可以引用了。 再者,返回引用效率高,不用拷贝一个新的,直接返回它自己。 而且,返回引用有助于连着调用。比如cout<<a<<b<<c<<d,为什么可以连着写?其实<<也是函数,为什么我们平时的函数一般不能连着写?如a.xx().xx().xx.()这样调用三个xx()。这也体现了引用的作用。 对于cout<<a<<b<<c<<d;就是
operator<<(operator<<(operator<<(operato<<(cout,a),b),c),d);
从左到右先执行cout<<a执行完了后返回cout的引用,就是cout本身,那么原式变为cout<<b<<c<<d; 紧接着这行cout<<b执行完再次返回cout........这样就把a,b,c,d依次作用到了cout,我们于是看到abcd连续输出了。
如你所说,cout<<a<<b<<c<<d;谭浩强说,先执行cout<<a,返回一个输出流对象(引用),然后这个新的cout对象(引用)又执行<<b,然后又返回一个新的cout对象(引用),直到输出完成。每输出一次,就返回一个新的输出流对象(引用),那每次输出流对象cout有啥不同。
一般可以认为第一次执行完cout直接将a输出到了屏幕,cout本身没有变化,然后执行b......
但是具体情况不是这样的。这要看c++的IO具体是怎么设计的。执行一次cout<<a并不一定直接将a输出到屏幕,而是将a转到IO的缓冲区,具体什么时候将a输出到屏幕要看系统什么时候有时间和c++的IO具体是怎么实现的。 系统掌握着消息队列,每次从里面抽取一条消息执行,因为CPU效率很高,我们感觉程序是连续运行的,其实不连续。对于多核处理器来说可以发生真实的同时执行几个程序。
要强制系统将数据输出到屏幕上,可以“刷新”一下,比如用cout<<endl;就是打一个换行,再刷新缓冲区,刷到屏幕上。
对于评论区的两点,解释一下:
重载<<流输出运算符,我是用于一个自定义类与ostream类,不是重载<<的移位运算等,不用做其他用法。 在我的编译器上不通过(VS2012和DEV c++都编译不通过)
我举得例子有错误,为了简便直接写的,现在发现是错的。因为都是A的对象相加,如果有两个参数,那么应该是友元函数,frined ......, 如果一个参数,可以声明为成员函数。
至于为什么返回引用也正常,这是由于:
“函数返回的临时变量是放在堆栈上的,所以返回来后如果你没有调用其他的函数,那么这个临时变量在依然保存在堆栈中,是可以被引用的。
因为这时堆栈并没有被破坏。但是一旦调用其他函数后堆栈被破坏了,那个返回值就没有用了”摘自“正心修身齐家治国平天下”的百度空间,可以看一下。
即使这样编译器也会给警告(WARNING),不建议这么写
如果在函数中没有产生新的对象,需要返回的是调用函数之前就存在的对象,就返回引用。
返回怎样的值,是基于需求考虑的,+-*/的结果,只需要临时使用,因此,返回对象就行了,至于返回引用,可以一方面可以继续处理,另一方面,没有复制拷贝的代价,更高效。