You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

赋值运算符重载返回Class、Class&、void的区别及返回必要性解析

赋值运算符重载:三种返回类型的区别与返回值意义

问题背景

给出的深拷贝Club类赋值运算符重载代码如下:

//deep copies one object into another
Club& Club::operator= (Club& obj) {
    this->members_ = std::unique_ptr <Member[]> (new (std::nothrow) Member[obj.num_members_]);
    if (members_ != nullptr) {
        this->num_members_ = obj.num_members_;

        for (int i = 0; i < obj.num_members_; i++) {
            this->members_[i] = obj.members_[i];
        }
    }

    else {
        std::cout << "Memory could not be allocated.\n";
        this->num_members_ = 0;
    }

    return *this;
}

疑问点:

  1. 使用Club(值返回)、Club&(引用返回)、void作为返回类型时代码均可运行,三者有何区别?
  2. 执行club200 = club200a;时已通过this修改了对象,未存储返回值,为何需要返回地址或值?
  3. 知道引用可用于运算符链式调用,但返回值实际会发生什么?
  4. 教授要求按值返回,该如何理解?

一、三种返回类型的核心区别

1. 返回void

  • 行为:赋值操作仅修改当前对象(*this)的状态,完成后不返回任何值。
  • 限制:完全禁用链式赋值(比如clubA = clubB = clubC;会直接编译报错),也无法将赋值结果作为右值传递给其他函数(比如func(clubA = clubB);)。
  • 场景:仅满足最基础的赋值需求,但不符合C++中赋值运算符的常规语义,实际开发中很少使用。

2. 返回Club(值返回)

  • 行为:返回当前对象的副本——会调用Club的拷贝构造函数,把*this复制一份后返回。
  • 代价:额外的拷贝开销(如果类成员多、深拷贝逻辑复杂,性能损耗会很明显)。
  • 特性:支持链式赋值,但链式中每一步都会产生临时对象。比如clubA = clubB = clubC;会先执行clubB = clubC,返回clubB的副本,再把这个副本赋值给clubA。
  • 注意:如果类没有正确实现拷贝构造函数,值返回可能会导致浅拷贝问题,引发内存泄漏或重复释放。

3. 返回Club&(引用返回)

  • 行为:返回当前对象的左值引用——直接指向*this本身,无拷贝开销。
  • 特性:完美支持链式赋值,且完全符合C++原生类型的赋值语义(比如int a = b = c;就是返回引用实现的)。链式调用中clubA = clubB = clubC;会先执行clubB = clubC返回clubB的引用,再把clubC的值赋值给clubA,全程无临时对象产生。
  • 优势:性能最优,是C++中赋值运算符重载的标准写法(几乎所有STL容器的赋值运算符都是返回引用)。

二、为什么需要返回值?

即使你写club200 = club200a;时没有存储返回值,返回值的存在是为了:

  1. 符合C++常规语义:原生类型(int、float等)的赋值操作本身会返回左值,比如int x; (x = 5) = 10;是合法的,最终x的值为10。用户会期望自定义类的赋值行为和原生类型一致。
  2. 支持链式操作:除了链式赋值,还可以将赋值结果作为参数传递给函数,比如print(clubA = clubB);,此时函数接收的是赋值后的clubA(引用返回)或其副本(值返回)。
  3. 代码灵活性:保留后续扩展的可能,比如未来需要在赋值后直接调用对象的成员函数:(clubA = clubB).addMember();,引用返回可以直接操作原对象,值返回则只能操作临时副本(操作完即销毁,意义不大)。

三、链式调用中返回值的实际行为

以clubA = clubB = clubC;为例:

  • 如果返回Club&:
    1. 先调用clubB.operator=(clubC),修改clubB的状态,返回clubB的引用;
    2. 再调用clubA.operator=(返回的clubB引用),修改clubA的状态,返回clubA的引用;
    3. 全程无临时对象,所有操作直接作用于原对象。
  • 如果返回Club:
    1. 调用clubB.operator=(clubC),修改clubB,返回clubB的副本(临时对象);
    2. 调用clubA.operator=(这个临时对象),修改clubA,返回clubA的副本;
    3. 临时对象在语句结束后销毁,造成额外的拷贝和析构开销。
  • 如果返回void:
    编译器直接报错,因为clubB = clubC没有返回值,无法作为clubA = ...的右值。

内容的提问来源于stack exchange,提问作者happy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 03:17:09