简体   繁体   中英

c++ operator += overloading return reference to

Could somebody explain what the difference is in this example of operator overloading, Average& operator+=(int num) where you return a reference to Average versus not returning a reference to Average ie Average operator+=(int num) .

Does returning a reference mean return a reference to the object being assigned to (not a copy) which is *this . So in this case return a reference to the object avg .

How/why does the non reference version work? Where is the result being copied?

#include <iostream>
#include <cstdint> // for fixed width integers

class Average
{
private:
    int32_t m_total = 0; // the sum of all numbers we've seen so far
    int8_t m_numbers = 0; // the count of numbers we've seen so far

public:
    Average()
    {
    }

    friend std::ostream& operator<<(std::ostream &out, const Average &average)
    {
        // Our average is the sum of the numbers we've seen divided by the count of the numbers we've seen
        // We need to remember to do a floating point division here, not an integer division
        out << static_cast<double>(average.m_total) / average.m_numbers;

        return out;
    }

    // Because operator+= modifies its left operand, we'll write it as a member
    Average& operator+=(int num)
    {
        // Increment our total by the new number
        m_total += num;
        // And increase the count by 1
        ++m_numbers;

        // return *this in case someone wants to chain +='s together
        return *this;
    }
};

int main()
{
    Average avg;

    avg += 4;
    std::cout << avg << '\n';


    return 0;
}

When overriding operators in C++, one can provide them in multiple forms. You can define assignment operators which do not return a reference to the modified object, and they would work as expected. But, we have for each operator what we call a canonical implementation :

Other than the restrictions above, the language puts no other constraints on what the overloaded operators do, or on the return type (it does not participate in overload resolution), but in general, overloaded operators are expected to behave as similar as possible to the built-in operators: operator+ is expected to add, rather than multiply its arguments, operator= is expected to assign, etc. The related operators are expected to behave similarly ( operator+ and operator+= do the same addition-like operation). The return types are limited by the expressions in which the operator is expected to be used: for example, assignment operators return by reference to make it possible to write a = b = c = d , because the built-in operators allow that.

Commonly overloaded operators have the following typical, canonical forms.

There is a lot to read about those canonical forms, but I'd suggest to start with this really good SO answer on What are the basic rules and idioms for operator overloading?


How/why does the non reference version work?

Because even if the C++ Standard encourages you to use the canonical forms, it doesn't forbid you not to.

Where is the result being copied?

Nowhere, the value is discarded. Implementation will probably optimize them away.

Does returning a reference mean return a reference to the object being assigned to (not a copy) which is *this. So in this case return a reference to the object avg.

Yes.

How/why does the non reference version work? Where is the result being copied?

The returned value is a temporary object that is passed to std::cout << .

It's similar to using:

int foo()
{
   return 10;
}

std::cout << foo() << std::endl;

The return value of foo is a temporary object that is passed to std::cout << .

You should return a reference because thats a convention most code in standard library is using, and most programmers do. Most programmers will expect below code:

std::string s;
(s += "a") = "b";
std::cout << s << std::endl;

to print b , or in this example:

int n = 10;
(n += 20) = 100;
std::cout << n << std::endl;

will expect 100 to be printed.

That is why you should return a reference to keep with the convention which allows to modify object which is on the left side of assignment.

Otherwise, if you return by value (a copy) assignment as in above examples will assign to a temporary.

Try to check this similar question .

When you return reference, you are actually passing the actual object. While when you return by value, temporary object is created and then passed to caller.

So if you return without reference this assignment may work as per your code segment above.

Average aa = avg += 4;

But it will fail to compile if you try.

Average *ptr = &(avg += 4);

The above code will work if you return reference though, since we are passing valid scope of object.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM