重载<<运算符为何需返回对象引用以支持链式调用?
关于ostream<<运算符重载与链式调用的问题解答
1. 为什么返回引用支持链式调用?
链式调用cout << coord1 << coord2本质是按左到右顺序执行,等价于:
operator<<(operator<<(cout, coord1), coord2);
第一个operator<<(cout, coord1)执行后,需要返回一个能被下一个operator<<接收的ostream对象。如果返回的是ostream&(也就是传入的cout的引用),第二个调用就直接用这个引用操作原cout对象,自然能连续完成输出。
2. 返回对象引用具体指什么?是返回cout的引用避免副本吗?
对,这里返回的就是传入的output参数的引用——也就是cout本身的引用(因为调用时第一个参数就是cout)。
返回引用而非值的核心原因有两个:
ostream类是不可拷贝的(它的拷贝构造函数被声明为delete),根本没法创建副本返回;- 就算能拷贝,返回值会产生临时对象,链式调用操作的是临时对象而非原
cout,不仅效率低,还可能出现输出顺序、流状态异常等问题。返回引用直接复用原对象,既高效又保证操作的是同一个流。
3. 编译器背后的具体原理
从编译执行逻辑看:
- 运算符
<<的结合性是左到右,编译器会先处理cout << coord1,再把这个结果作为第二个<<的左操作数; - 当函数返回
ostream&时,编译器不会创建新对象,而是直接返回原ostream对象的内存地址别名(引用就是变量的别名),后续调用直接操作原对象; - 如果返回的是
ostream值,编译器会尝试调用ostream的拷贝构造函数创建临时对象,但因为ostream禁止拷贝,编译阶段就会报错,根本到不了链式调用的执行环节。
4. 移除引用后无法链式调用的原因
改成ostream operator<<(ostream &output, coords coord)后,有两个致命问题:
- 首先,
ostream不允许拷贝,尝试返回值时编译器会直接报错(因为要调用被禁用的拷贝构造函数),连编译都通不过; - 退一步假设能拷贝(比如自定义可拷贝的流类),第一个调用返回的是临时
ostream对象,而operator<<的第一个参数是ostream&(非const左值引用),C++不允许将临时对象绑定到非const左值引用,第二个<<调用会因参数不匹配报错,自然无法链式调用。
内容的提问来源于stack exchange,提问作者Colors
相关产品推荐
相关产品推荐

