运算符重载,运算符+vs运算符+=

Operator overloading, operator+ vs operator+=

本文关键字:运算符 重载 +vs      更新时间:2023-10-16

我读了一些c++源代码,发现了一些语法。

path& path::operator+=(string postPath)

我想知道这是否是实际的语法,以及为什么c++没有使用已经存在的运算符+,而是将值应用于所讨论的对象。

如果你想确保对象被正确删除,这是不是很像。但析构函数应该处理所有这些。

-Edit1

我知道a+=b之间有区别;和a+b
我想知道的是,为什么c++不只是将运算符+与==一起使用,而不必将运算符==重新定义为与运算符+相同

-Edit2

我不确定它的含义是否正确,但我想问的是,为什么这种语言不能基于+来推断+=。现在我意识到+=的其他用途。感谢大家:)

  1. 可能存在效率问题;如果对象的复制/分配成本很高,a+=b可能会为您节省一个临时构造、一个复制构造和一个分配,并使您能够更好地利用目标对象中已有的资源。如果std::vector有一个+=运算符来连接向量,那么直接实现它(你可以利用目标对象的额外容量,避免无用的分配)会更有效,而不是创建一个临时和向量("从头开始")并分配它。

    实际上,通常我用+=来实现+,通常它会产生更高效、更容易编写的代码;像这样:

    T &operator+=(const T &r)
    {
        // say that T encapsulates an N-dimensional array
        for(int i=0; i<N; ++i)
            arr+=r.arr[i];
        return *this;
    }
    T operator+(const T &r)
    {
        T ret(*this);
        ret+=r;
        return ret;
    }
    

    (尽管我同意有一种方法可以要求编译器从现有运算符合成+/-;关系运算符也是如此)

  2. 您可能想要一个可以添加但无法复制/分配的对象。例如,对于我的一个玩具项目,我曾短暂考虑过让信号对象(比如boost或Qt,或者.NET事件/多播委托)过载+=来添加连接(Signal &operator+=(std::function<T...> fn)),但我不想处理分配/复制语义(信号的IMHO没有意义);

  3. 最重要的是,在C++中,你可以重载(几乎)所有运算符,让它们做任何你想做的事情,而不需要特别的语义限制。您可以编写一个发射火箭的operator+和一个删除硬盘上所有文件的operator+=——由您负责,如果这在您的应用程序中有意义,您可以自由执行,无需特别限制。

C++对重载运算符没有做出任何假设;你可以例如定义一个不可交换的operator+。你呢可以定义与CCD_ 14没有关系的CCD_。也可以在不定义operator+的情况下定义operator+=,反之亦然反之亦然。

至于原因:对于初学者来说,你真的不希望编译器假设字符串上的operator+是可交换的,并因此优化。一旦打开大门,语言的作者们无疑我觉得最好由程序员来决定,而不是在语言层面强加任何东西。即使我想不出一个案例在某些情况下,支持+=和CCD_ 19,语义略有不同。C的一般哲学++一直致力于为程序员提供所需的所有工具编写好的代码,但不要禁止不符合当前规范的代码什么是坏代码。(从长远来看,这是有回报的,因为我们关于什么是好代码,什么是坏代码的想法已经形成。)

是的,对于string添加到path上的情况,path& path::operator+=(string postPath);有效并且重载+=运算符。

您希望能够重载它的原因很简单:operator+必须返回一个新值,而不是更改旧值,而operator+=可以重用现有资源(例如分配的内存)。由于附加字符串的主要操作(这就是您正在做的)是内存分配,因此在您的实际情况下,+=的性能可能会高得多。

此外,操作SomePath + SomeString提出了SomeString + SomePath的问题,更糟糕的是,SomeStringA + SomePathB的问题,所有这些都略有不同,而SomePath += SomeString具有非常明确的含义。

既然现在应该清楚为什么希望能够在不实现+的情况下实现+=,那么考虑另一个方向:为什么不将a = a + b用作a += b:的默认实现

首先,运算符重载规则早于= delete。因此,即使在您根本不希望operator+=存在的情况下,该规则也将始终触发。注意,实现"默认"非常简单:

A& operator+=(A const& other) { return *this = *this + other; }

为什么c++没有使用已经存在的运算符+,而是结合应用值

正是因为+=发生突变,而+没有。这往往意味着在执行方面存在重大差异。

a += b实现为a = a+b的效率低于直接实现,因为它必须创建并销毁分配给a的临时对象。

+= 实现+更有效

path operator+(path prePath, string postPath) {
    return prePath += postPath;
}

从哲学上讲,有人可能会说,如果语言没有神奇地生成你可能想不到的运算符,那就不那么令人惊讶了。许多人会被隐式生成的构造函数和赋值运算符给他们的类型提供无效的复制语义所困扰(直到他们学会了三规则),而其他神奇的行为可能会以其他方式引起混乱。