debonair
debonair

Reputation: 2593

const return type in operator overloading

const Byte operator/(const Byte& right) const {
    require(right.b != 0, "divide by zero"); 
    return Byte(b / right.b); 
} 

I read that If the effect of the operator is to produce a new value, you will need to generate a new object as the return value. For example, Integer::operator+ must produce an Integer object that is the sum of the operands. This object is returned by value as a const, so the result cannot be modified as an lvalue.

What if we don't write it as const? Any example with explanation would be helpful.

Also why do we have second const in function prototype?

Upvotes: 3

Views: 2053

Answers (2)

Mike Seymour
Mike Seymour

Reputation: 254431

Any example with explanation would be helpful.

This is outdated advice, intended to make the operator behave somewhat like the built-in operator so that nonsense like (a / b) = c won't compile.

However, since C++11, it also inhibits move semantics, which can hurt efficiency; so you shouldn't return a const value.

Also why do we have second const in function prototype?

The argument is a const reference, and the member function is const, to (a) ensure that the operator doesn't modify either operand; and (b) allow it to be called with constant or temporary operands.

To elaborate on (b), without these const qualifiers, you wouldn't be able to use constant operands:

const Byte a, b;
a / b;  // ERROR: operands can't be const

or temporary values:

Byte f();
f() / f();  // ERROR: operands can't be temporary

Upvotes: 9

Mr.C64
Mr.C64

Reputation: 42924

For binary operators, I'd prefer defining a "free" (non-member) function (that may be friend of the class on which it operates, in case it needs to directly access the private or protected data members of the class):

class Byte {
  ....

    friend Byte operator/(const Byte& left, const Byte& right) {
        require(right.b != 0, "divide by zero"); 
        return Byte(left.b / right.b); 
    }
};

Both left and right parameters are passed by const & because:

  • they are read-only input parameters, so mark them as const
  • you don't want to make useless deep-copies (assuming that they are not cheap), so use reference &

Anyway, if your Byte class just wraps an 8-bit byte, and the copy constructor is a trivial one-byte copy, you can simplify your code and just pass by value:

friend Byte operator/(Byte left, Byte right) {
    require(right.b != 0, "divide by zero"); 
    return Byte(left.b / right.b); 
}

Upvotes: 1

Related Questions