简体   繁体   中英

Overloading operators + and - in C++

I have two questions about overloading.

1- Why sometimes do make overloading operators non-member functions?

friend Class operator-(const Class &rhs);

2- What's the difference between

Class operator+(const Class &c1, const Class &c2);

and

Class operator+(const Class &rhs);

if I want to add two objects C3 = C1 + C2 ?

Any help is appreciated...

If you overload a binary operator as a member function, it ends up asymmetrical: the left operand must be the exact type for which the operator is overloaded, but the right operand can be anything that can be converted to the correct type.

If you overload the operator with a non-member function, then both operands can be converted to get the correct type.

What you have as your second point looks like a concrete example of the same point, not really anything separate at all. Here's a concrete example of what I'm talking about:

class Integer {
    int val;
public:
    Integer(int i) : val(i) {}
    operator int() { return val; }

    // Integer operator+(Integer const &other) const { return Integer(val + other.val); }

    friend Integer operator+(Integer const &a, Integer const &b) { 
        return Integer(a.val + b.val);
    }
};


int main() { 
    Integer x(1);

    Integer y = x + 2; // works with either operator overload because x is already an Integer

    Integer z = 2 + x; // works with global overload, but not member overload because 2 isn't an Integer, but can be converted to an Integer.
    return 0;
}

Also note that even though the definition of the friend function is inside the class definition for Integer , the fact that it's declared as a friend means it's not a member function -- declaring it as friend makes it a global function, not a member.

Bottom line: such overloads should usually be done as free functions, not member functions. Providing the user with an operator that works correctly (drastically) outweighs theoretical considerations like "more object oriented". When necessary, such as when the implementation of the operator needs to be virtual, you can do a two-step version, where you provide a (possibly virtual) member function that does the real work, but the overload itself is a free function that invokes that member function on its left operand. One fairly common example of this is overloading operator<< for a hierarchy:

class base { 
    int x;
public:
    std::ostream &write(std::ostream &os) const { 
        return os << x;
    }
};

class derived : public base { 
    int y;
public:
    std::ostream &write(std::ostream &os) const { 
        return (base::write(os) << y);
    }
};

std::ostream &operator<<(std::ostream &os, base const &b) {
    return b.write(os);
}

This supports both polymorphic implementation (and access to a base class' protected members, if necessary) without giving up the normal characteristics of the operator to get it.

The primary exceptions to overloading binary operators as free functions are assignment operators ( operator= , operator+= , operator-= , operator*= and so on). A conversion would produce a temporary object, which you can't assign to anyway, so for this particular case, the overload should be (must be, as a matter of fact) a member function instead.

1-Why sometimes do make overloading operators non-member functions?

It's matter of choice. You can either make the operator +/- a class member or make it a free friend function.
The syntax you provided for operator - is wrong if it's a free friend function, it should take 2 arguments (similar to operator + in your example).

2- What's the difference between

As said before, it's just a syntax different. The first one should be a free friend function and the second one is a class member.

On top of that, I believe keeping an operator as class member method is superior compared to free function because:

  1. Member method can access the protected members of base class if applicable, but the friend function cannot
  2. Member method is more object oriented approach because you associate a method which relates to a class

Making the overloaded operator a friend is a better option because take this example

class Comples
{
   public:
      Complex(float real, float imaginary);
      friend operator+ (const Complex &rhs);
   ...
};

By having the operator a friend you can do the following

Complex result1 = 5.0 + Comples(3.0, 2.0);

and

Complex result1 = Comples(3.0, 2.0) + 5.0;

Which obeys the rules of additions communitivity property. This cannot be achieved if the overloaded operator is a member function. This is due to the compiler able to implicitly create a Complex object asrequired in this case. Thus the addition operator when being a friend acts in accordance with the normal notion of addition in mathematics.

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