C++重载<<运算符链式调用未达预期效果的原因咨询
C++运算符重载链式调用失效:值返回与引用返回的原理差异
问题描述
我是一名正在学习C++运算符重载的学生,遇到了链式调用运算符重载时结果不符合预期的问题。我重载<<运算符用于将整数加到类实例的所有成员变量上,期望链式调用a <<3<<5<<6后,原对象的成员会累加所有数值,但实际只有第一个操作生效。
问题代码
#include <iostream> using namespace std; class Power { int kick; int punch; public: Power(int kick = 0, int punch = 0) { this->kick = kick; this->punch = punch; } void show(); Power operator << (int n); }; void Power::show() { cout << "kick=" << kick << ',' << "punch=" << punch << endl; } Power Power::operator <<(int n) { kick += n; punch += n; return *this; } int main() { Power a(1, 2); a << 3 << 5 << 6; a.show(); }
预期与实际结果
- 预期输出:
kick=15,punch=16 - 实际输出:
kick=4,punch=5
已知将运算符重载的返回类型改为Power& operator << (int n);可以修复问题,但不清楚两种写法的原理差异。
原理解释
1. 返回值类型(Power)的问题根源
当operator<<返回值类型时,每次调用都会创建并返回当前对象的副本:
- 链式调用
a <<3<<5<<6的执行顺序是从左到右拆解为:((a <<3) <<5) <<6- 第一步
a <<3:修改原对象a的kick和punch(变为4、5),然后返回a的副本; - 第二步
(a<<3) <<5:操作的是第一步返回的临时副本,修改的是副本的成员,和原对象a完全无关; - 第三步
((a<<3)<<5) <<6:操作的是第二步副本的新副本,所有后续修改都不会影响原对象a。
- 第一步
- 临时副本在语句执行结束后会被销毁,所以原对象
a只保留了第一次操作的结果。
2. 返回引用类型(Power&)的修复原理
当返回类型改为引用类型时,operator<<返回的是当前对象本身的引用,而非副本:
- 链式调用的每一步操作都会直接作用在原对象
a上:- 第一步
a <<3:修改原对象a,返回a的引用; - 第二步
(a<<3) <<5:等价于直接对a执行<<5操作,继续修改原对象; - 第三步
((a<<3)<<5) <<6:等价于直接对a执行<<6操作,最终原对象的成员会累加所有数值。
- 第一步
- 这种方式既保证了链式调用的正确性,还避免了不必要的对象拷贝开销,是修改类成员的运算符重载的常规设计方式。
内容的提问来源于stack exchange,提问作者KnightChaser
相关产品推荐
相关产品推荐

