0

I have been looking at some open source code and I see two different definitions of overloading an operator. What is the difference between them and are there any benefits of doing either?

For example, one example we have a class:

class foo{
public:
    void SetValue(double input_value) {foo_value = input_value};
    double GetValue() {return foo_value;}
private:
    double foo_value;
};

Then I sometimes see two different types / styles of overloading the addition operator (for example)

class foo{
    const foo operator+(const foo& input_foo);
};

const foo foo::operator+(const foo& input_foo) {
    foo_value += input_foo.foo_value;
    return *this;
}

The other type of overload I sometimes see is:

class foo{
    friend const foo operator+(const foo& input_foo1, const foo& input_foo2);
};

const foo operator+(const foo& input_foo1, const foo& input_foo2); // Defined right after class

const foo operator+(const foo& input_foo1, const foo& input_foo2) {
    foo temp_foo;
    temp_foo.SetValue(input_foo1.GetValue() + input_foo2.GetValue());
    return temp_foo;
}
David G
  • 94,763
  • 41
  • 167
  • 253
user2840470
  • 919
  • 1
  • 11
  • 23
  • 4
    Your first version of `operator+` is completely wrong. – T.C. Jan 06 '15 at 15:31
  • 1
    possible duplicate of [Operator overloading](http://stackoverflow.com/questions/4421706/operator-overloading) – nbro Jan 06 '15 at 15:34
  • You typically define them as outside-of-class methods with two arguments. On one hand that indicates they're not a fundamental part of that class but only use its public API, and on the other hand it also works if the left-hand side is not your class (but for example, an int). – dascandy Jan 06 '15 at 15:38
  • @T.C. It would be helpful if you also provide the problem with first version. – ravi Jan 06 '15 at 15:40
  • @ravi The problem is the member function should be defined as const and not modify the object in question (as implemented it's more like operator +=). Define it as `const foo operator+(const foo& input_foo) const;` and use the same implementation as the free function. – Jason Jan 06 '15 at 15:43
  • @dascandy So would you say it would be beneficial to use the second type if wanting to +- ints or doubles as well. And use first type if only doing foo +- foo? – user2840470 Jan 06 '15 at 15:49
  • @user2840470 Yes, exactly that. – dascandy Jan 06 '15 at 16:26

2 Answers2

3

One overload is member function whereas other is free function.

You use free function so as to provide mixed-mode arithmetic. For e.g:-

foo f;
2 + f;    __1

__1 would compile only if there is free function operator+. Member function operator+ won't do anything in this case.

ravi
  • 10,994
  • 1
  • 18
  • 36
  • @Rinzler A non-member function. – David G Jan 06 '15 at 15:36
  • @0x499602D2 Why inventing new names, if the real name is `friend function`, no? – nbro Jan 06 '15 at 15:37
  • @Rinzler You don't want to make it friend if it can be implemented completely in terms of class public interface... – ravi Jan 06 '15 at 15:38
  • @Rinzler A friend function isn't necessarily a non-member function (that is, it can be a member function). And a non-member function doesn't equate to friend function. – David G Jan 06 '15 at 15:38
  • 2
    @Rinzler: It's not a new name. The term has been around for quite some time. – Benjamin Lindley Jan 06 '15 at 15:39
  • @0x499602D2 Who said that (the opposite of what you said), me? – nbro Jan 06 '15 at 15:39
  • @Rinzler That's what I was picking up. – David G Jan 06 '15 at 15:42
  • @ravi that makes sense, so if I am only doing foo +- foo, I should probably just the first type of definition? But if I want to do int +- foo or foo +- int, I would have to use the second type? – user2840470 Jan 06 '15 at 15:51
  • @user2840470 Only to support int + foo, second version is justified. foo + int can be done using first version also. Remember you have to provide single argument non-explicit constructor in either of the cases. – ravi Jan 06 '15 at 15:53
0

By an external point of view, foo::operator+(const foo&) and ::operaor+(const foo&, const foo&) plays exactly the same role in making meaningful the + symbol when placed between two foo-s. In particular the first is like the second when its own fisrt argument is *this.

By an internal point of view, they can have different capabilities in respect to the foo class: ::operaor+(const foo&, const foo&) is a "free function" (a function declared at global level): it has the beauty of the symmetry in treating the arguments in the same way, but cannot access foo's private data member, unless foo itself doesn't recognize it as its own firend.

foo::operator+(const foo&), as a member function, can have free access to all foo members and data but -as a member of foo- is less suitable to "generic algorithms" (that may prefer a functional form).

There are also some other difference about possible variants: consider

foo a;
foo b;
int k;

Both the operator+ seen above can give meaning to a+b, but what about a+k and k+a?

For a+k you can have either foo::operator+(int) or ::operator+(const foo&, int), but for k+a, you need ::operator+(int, const foo&) since there is no way to have + as a meber of int.

All that said, you declaration and implementation look "fuzzy" (or at least incoherent):

const foo foo::operator+(const foo& input_foo) {
    foo_value += input_foo.foo_value;
    return *this;
}

When you write c = a+b do you expect the value of a to change?

What you do, here, is adding b to a and create a copy of a (why const? it's a copy after all, and you already changed a) you assign then to c.

Operator + should create a new object whose value is the sum

foo foo::operator+(const foo& rop) const // NOTE THE SIGNATURE, make it coherent with the decalration { foo tmp; tmp.foo_value = foo_value + rop.foo_value; return tmp; }

It's not the return type, but the member-function itself to be const, as the parameter if given by reference, so that you ensure that in a+b neither a or b is changed. The return type is just a plain value you can let your caller to treat as it wants, since it is returned into his own stack-frame.

Emilio Garavaglia
  • 20,229
  • 2
  • 46
  • 63