C++中operator+=重载返回引用与返回值的区别解析
运算符重载中
operator+=返回引用与非引用的区别解析 咱们直接把这两种写法的核心差异、工作逻辑掰扯清楚,结合代码示例一看就明白:
一、返回引用的版本:Average& operator+=(int num)
没错,这个版本返回的就是被赋值对象(也就是*this,比如你代码里的avg)的引用,完全不是副本。
工作逻辑:
在函数内部修改完当前对象的成员变量(比如总和、计数)后,直接return *this;——这里返回的是当前对象的别名,相当于给原对象起了个“外号”。外界拿到这个返回值时,操作的还是原来的那个对象,没有任何拷贝动作。
核心优势:
- 支持链式调用:比如你可以写
avg += 5 += 3,这个语句会先执行avg +=5(修改原对象),然后返回的avg引用再执行+=3,最终avg会包含两次累加的结果。 - 无拷贝开销:尤其是当
Average对象比较大(比如包含大量成员、动态内存)时,避免拷贝能显著提升效率。 - 符合C++惯例:标准库中所有的
+=类运算符(比如std::string::operator+=、std::vector::operator+=)都是返回引用的,这样写能让代码风格更统一。
二、非引用版本:Average operator+=(int num)
这个版本的工作逻辑就不一样了——它返回的是当前对象的副本,而非原对象本身。
工作流程:
- 函数内部同样会修改当前对象的成员变量(比如给
sum加num,count加1); - 函数执行到
return *this;时,会调用Average的拷贝构造函数,把当前的*this复制出一个全新的临时对象; - 这个临时对象就是函数的返回值:
- 如果你没有用变量接收它,这个临时对象用完就会被销毁;
- 如果用
Average temp = avg +=10;接收,temp就是一个独立的新对象,和原avg完全没关系。
问题与局限:
- 链式调用失效:比如
avg +=5 +=3,第一个avg +=5会返回avg的副本,然后+=3修改的是这个副本,原对象avg只会保留第一次累加的结果,第二次操作和它无关。 - 额外的拷贝开销:每次调用都会生成临时对象,对性能不友好,尤其是对象复杂时。
- 不符合直觉:用户调用
avg += num时,预期的是修改avg本身,而非生成一个新对象,这种写法容易造成误解。
代码示例对比
#include <iostream> using namespace std; class Average { private: int sum = 0; int count = 0; public: // 返回引用的版本(注释掉可以切换到非引用版本测试) Average& operator+=(int num) { sum += num; count++; return *this; } // 非引用版本 /* Average operator+=(int num) { sum += num; count++; return *this; } */ double getAvg() const { return count == 0 ? 0 : static_cast<double>(sum)/count; } }; int main() { Average avg; avg += 5 += 3; // 返回引用时:avg的sum=8,count=2,输出4.0 // 非引用时:avg的sum=5,count=1,输出5.0(第二个+=3修改的是副本) cout << avg.getAvg() << endl; return 0; }
总结
| 写法 | 返回内容 | 链式调用支持 | 拷贝开销 | 适用场景 |
|---|---|---|---|---|
Average& operator+= | 原对象的引用 | 完全支持 | 无 | 绝大多数场景,符合C++惯例 |
Average operator+= | 原对象的副本 | 不支持(或不符合预期) | 有 | 几乎不推荐,除非有特殊需求(比如需要保留原对象,返回修改后的新对象,但这更适合operator+而非operator+=) |
内容的提问来源于stack exchange,提问作者lotto 1988
相关产品推荐
相关产品推荐

