0

I understand how polymorphism and inheritance works in C++, but my problem is: how do you make operators polymorphic for the following specific example?

Say I have a Foo class and two Foo instances, fooA and fooB. I want to redefine the plus sign operator so that "fooA + fooB;" does something specific to Foo instances (whatever that may be). How would the function prototype look? It's confusing me because I'm used to functions starting with a letter... Any help would be greatly appreciated.

By the way, this isn't a homework question -- more like a wonderment (I was thinking about polymorphism in Ruby).

boo-urns
  • 10,136
  • 26
  • 71
  • 107
  • 3
    [Operator Overloading](http://stackoverflow.com/questions/4421706/operator-overloading) should be a good read for you. – Alok Save Sep 14 '11 at 07:37
  • Operators infact are functions and your overloaded `+` operator can also be invoked as `fooAObj.operator+(fooBObj)` – Alok Save Sep 14 '11 at 07:41

3 Answers3

4

Example from http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/topic/com.ibm.xlcpp8a.doc/language/ref/cplr318.htm:

#include <iostream>
using namespace std;

class complx 
{
      double real, imag;
public:
      complx(double real = 0., double imag = 0.); // constructor
      complx operator+(const complx&) const;      // operator+()
};

// define constructor
complx::complx(double r, double i)
{
      real = r; imag = i;
}

// define overloaded + (plus) operator
complx complx::operator+(const complx& c) const
{
      complx result;
      result.real = this->real + c.real;
      result.imag = this->imag + c.imag;
      return result;
}

int main()
{
      complx x(4,4);
      complx y(6,6);
      complx z = x + y; // calls complx::operator+()
}
Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
  • 2
    Ah, "operator overloading"! That's what it's called!! Thanks so much. "polymorphism plus operator cpluplus" wasn't getting me anywhere. :P – boo-urns Sep 14 '11 at 07:29
  • 2
    it's better to have the the operator + return a const complx, else one can write nonsense like ( a + b ) = c; – stijn Sep 14 '11 at 07:31
  • 2
    It's preferred to make it a global instead of a member function, that way the first parameter (i.e. `*this`) can be coerced. – Oscar Korz Sep 14 '11 at 07:32
  • 1
    That's probably because overloading isn't polymorphic. – Keith Layne Sep 14 '11 at 07:36
  • keith, that is confusing to me. Some of the first examples I find when looking up polymorphism describes operator overloading behavior (e.g. adding ints versus concatenating strings). Also: http://en.m.wikipedia.org/wiki/Operator_overloading So, what do you mean by your comment? – boo-urns Sep 14 '11 at 07:43
  • My understanding: Overloading is independent of polymorphism. Overloading adds a new function definition that is independent of the original. Polymorphism allows foo(base) to be called with a derived parameter. There's only one foo(). – Oscar Korz Sep 14 '11 at 07:47
  • I didn't like the fact that `operator+` is a member function of `complx`. Ideally, a member function is supposed to be of two types: mutator or inspector; that is, one which modifies the object's state or, other which inspects the object. `operator+` does neither of them. For example, is the operation applied on `this` object? No. There it should be non-member function, as I've explained this in detail [here](http://stackoverflow.com/questions/7376554/functions-with-return-values-c/7376713#7376713) – Nawaz Sep 14 '11 at 07:47
  • @keith That's where your comment confused me. You said that overloading isn't polymorphic: That's probably because overloading isn't polymorphic. Are you saying it's not a type of polymorphism? If so, I'd like to know why you're saying it's not especially because someone upvoted your comment. – boo-urns Sep 15 '11 at 04:51
  • @Rachel In C++ when we talk about polymorphism we are usually talking about *parametric* polymorphism (templates) or *subtype* polymorphism (virtual functions, etc.). Operator overloading is pure syntactic sugar in C++. Call it 'ad-hoc polymorphism' if you want, but all you're really doing is defining a new function with (in this case) infix syntax. It can be argued forever, and I'm not interested in doing that, but I say overloading is not really polymorphic. – Keith Layne Sep 15 '11 at 07:23
3

const Foo operator+(const Foo& a, const Foo& b) is the correct signature. It will need to be a friend function if the data is private and has no mutator functions (that is, "setters").

Operators should be global functions instead of members in order for the the first parameter to be coerced to your type. For example, if int can be coerced to Foo, this is legal with the above signature: 1 + foo.

Edit: Code demonstrating why operator+ should be global...

struct Foo {
    int i;

    Foo(int i) : i(i) {}

    const Foo operator+(const Foo& a) {
        return Foo(this->i + a.i);
    }
};

int main() {
    Foo f(5);
    f + 1;
    1 + f; // g++ 4.5 gacks here.
    return 0;
}

Here's the error:

main.cpp: In function ‘int main()’:
main.cpp:14:9: error: no match for ‘operator+’ in ‘1 + f’
Oscar Korz
  • 2,457
  • 1
  • 18
  • 18
  • 2
    Or you could do it as a member function and have a non-`explicit` conversion constructor. – Keith Layne Sep 14 '11 at 07:34
  • No, the compler won't coerce the first argument in order to resolve operator overloads that are members. It doesn't matter if the constructor is explicit or not. I have verified this with g++ 4.5. – Oscar Korz Sep 14 '11 at 07:53
  • Right on. What I do in practice depends on the situation. I'd agree that this is best practice for numeric types, where coercion from primitives makes sense. IMO you shouldn't abuse the accepted meaning of the symbol. For some applications, `1 + foo` makes sense...but for many it doesn't. – Keith Layne Sep 14 '11 at 08:09
  • I can't think of many situations where `f + 1` make sense but `1 + f` doesn't. You should either allow coercion on the both operands or no coercion on both operands. Don't allow coercion on only one of them (e.g. the right operand). It will surprise users. – Oscar Korz Sep 14 '11 at 16:33
  • I agree...I guess I worded that poorly. In my comment you can read `1 + foo` as equal to `foo + 1`. I didn't mean to suggest that an operator overload should always (or ever) be a member, I was just throwing out an idea. My main point is that we should avoid abusing the normal semantics of the operator just to add syntactic sugar. – Keith Layne Sep 15 '11 at 04:10
  • Ah, ok. I completely agree with you. – Oscar Korz Sep 15 '11 at 15:35
1

For binary +, you need some form of double dispatch, which isn't supported out of the box by C++. There are several ways of implementing this, all with various disadvantages. And regardless of how you implement the double dispatch itself, for n different derived types, you will need n2 different functions.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • 1
    While it's true that double dispatch isn't natively supported in C++, I don't think that's what this question is about. – Oscar Korz Sep 14 '11 at 07:34
  • While you are correct, it seems the question was not necessarily about a dynamic polymorphism and static polymorphism (operator overloading) is enough for OP (who is probably trying to grasp basic C++ concepts now). – Suma Sep 14 '11 at 07:42
  • The original poster asked specifically about polymorphism. (Maybe he was confused about what he wanted to do.) – James Kanze Sep 14 '11 at 08:40