《Effective C++》《构造/析构/赋值运算——10、令operator=返回一个reference to *this》

1、Terms 10:Have assignment operators return a reference to *

关于赋值,有趣的是你可以把它们写成连锁形式,这是因为赋值运算符在每回赋值之后应该是返回“=”操作符左边的对象。如:

int x, y, z;
x = y = z = 5;

上面的“x=y=z=5”的意思是先将5赋值给z然后返回对象z,再将z对象赋值给y然后返回对象y,再将对象y赋值给对象x,最终这个表达式的结果是x。
  为了实现“连锁赋值”,赋值操作符必须返回一个 reference 指向操作符的左侧实参。
class 内实现赋值操作符时应该遵循的协议:
  我们建议在重载类的operator=运算符时,应该让这个运算符返回一个*this(指向于自己的类型的引用。
  
示例:

class Widget {
public:
    Widget& operator=(const Widget& rhs)
    {
        return *this; //返回左侧对象
    }
};

对于上面的operator=运算符,其设计规则还适用于其他辅助运算符(例如:+=、-=、*=、/=等等),例如:

class Widget {
public:
    Widget& operator+=(const Widget& rhs)
    {
        return *this;
    }
    Widget& operator=(int rhs)
    {
        return *this;
    }
};

令赋值操作运算符返回一个reference to *this。虽然这个建议不是强制性的,但是建议这么使用,例如所有内置类型和标准程序库的string、vector等都是这么遵守的。

2、面试相关

在C++中,return *this是一个常见的模式,尤其在实现链式调用(chaining)的设计模式时。以下是关于return *this的一些高频面试问题及其解答:

面试问题1:请解释return *this在C++中的作用是什么?

解答
在C++中,return *this用于在成员函数中返回当前对象的引用。这通常用于实现链式调用,即允许在一个成员函数调用之后直接调用另一个成员函数,而无需使用中间变量。通过返回对象的引用,我们可以连续调用成员函数,从而实现更流畅、更易于阅读的代码。

面试问题2:return *thisreturn this有什么区别?

解答
return *this返回的是当前对象的引用(即对象本身),而return this返回的是指向当前对象的指针。具体区别如下:

  • return *this:返回对象的引用,这意味着你可以直接通过返回的引用修改对象的状态。此外,如果你返回的对象是自定义类型,那么返回引用可以避免不必要的拷贝操作,提高效率。在链式调用中,返回引用是必要的,因为你需要返回一个可以进一步调用成员函数的对象。
  • return this:返回指向对象的指针。虽然它也可以用于链式调用(因为指针也可以解引用并调用成员函数),但它通常不如返回引用直观和方便。此外,使用指针可能会增加出错的机会,例如空指针解引用等问题。

面试问题3:为什么在实现链式调用时通常使用return *this而不是return this

解答
链式调用的核心思想是允许我们连续调用成员函数,而不需要在每个调用之间使用中间变量。为了实现这一点,我们需要从每个成员函数中返回一个可以继续调用成员函数的对象。由于指针需要解引用才能调用成员函数,而引用可以直接调用,因此使用return *this(即返回对象的引用)更为直观和方便。此外,返回引用还可以避免不必要的拷贝操作,提高代码效率。

面试问题4:请给出一个使用return *this实现链式调用的例子。

解答
以下是一个简单的例子,展示了如何使用return *this实现链式调用:

#include <iostream>
using namespace std;

class Test {
private:
    int a;
    int b;
public:
    Test() : a(0), b(0) {}
    
    Test& AddA(int val) {
        a += val;
        return *this;
    }
    
    Test& AddB(int val) {
        b += val;
        return *this;
    }
    
    void Print() {
        std::cout << "a: " << a << ", b: " << b << std::endl;
    }
};

int main() {
    Test t;
    t.AddA(1).AddB(2).Print();  // 输出: a: 1, b: 2
    return 0;
}

在这个例子中,AddAAddB成员函数都返回*this,这使得我们可以连续调用它们,并在最后调用Print函数打印结果。这就是链式调用的一个简单示例。

3、总结

天堂有路你不走,地狱无门你自来。

4、参考

4.1《Effective C++》

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-06 02:26:03       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-06 02:26:03       106 阅读
  3. 在Django里面运行非项目文件

    2024-04-06 02:26:03       87 阅读
  4. Python语言-面向对象

    2024-04-06 02:26:03       96 阅读

热门阅读

  1. postcss安装和使用

    2024-04-06 02:26:03       40 阅读
  2. 【WPF应用26】C#中的CheckBox控件详解与应用示例

    2024-04-06 02:26:03       43 阅读
  3. 热浪

    2024-04-06 02:26:03       30 阅读
  4. WebView的使用和后退键处理

    2024-04-06 02:26:03       44 阅读
  5. 蓝桥杯每日一题:转圈游戏(快速幂)

    2024-04-06 02:26:03       37 阅读
  6. SpringBoot 接口加密解密

    2024-04-06 02:26:03       32 阅读
  7. “全双工“是什么

    2024-04-06 02:26:03       39 阅读
  8. 【C/C++】数组模拟数据结构

    2024-04-06 02:26:03       39 阅读
  9. 安卓APP的技术质量:如何提高

    2024-04-06 02:26:03       35 阅读
  10. 函数model. addGenConstrMax

    2024-04-06 02:26:03       44 阅读
  11. C# 静态方法的小芝士

    2024-04-06 02:26:03       36 阅读
  12. Vue3:重构Pinia的store,使用组合式写法实现

    2024-04-06 02:26:03       41 阅读