Why does my operator overloading handle left versu

2019-08-21 07:58发布

问题:

I had a question on operator overloading. Below is my the example code. If you can read through it and my question is below.

//class definition
class example
{
private:
    int a ; // Defined in FeetInches.cpp
public:
    void seta(int f)
    {
        a = f;
    }
    example operator + (const example &); // Overloaded +

    int geta()
    {
        return a;
    }
};

example example::operator + (const example &right)
{
    example temp;

    temp.a = a + right.a;
    return temp;
}

//main

#include "header" //this is the class definition above
#include <iostream>
using namespace std;

int main()
{
    example r;
    r.seta(1);

    example s;
    s.seta(1);

    example t;
    t = r + s;
    t = r + 1;  //if included it won't compile
    t = 1 + r; //if included it won't compile

    int x = t.geta();
    cout << x;

    cin.get();
    return 0;
}

I understand that when you attempt to add to objects together using operator overloading they should be the same.

Here is the question: I recently saw when the object was on one side of the operator it compiled but when it was on the other it didn't. Such as:

t = r + 1; it compiled. t = 1 + r; it didn't.

(Also I know in my example it doesn't work either way but was just easier to frame question with code.)

How does operator overloading compile when the object is on one side of the operator but not compile when it is on the other.

Thanks

回答1:

t = r + 1; means t = r.operator+(1); if r defines a matching operator+() method, otherwise it means t = operator+(r, 1); instead. It does not compile because you did not define any + operator that takes an example on the left and an int on the right, eg:

// as a class method:

class example
{
    ...
public:
    ...
    example operator + (int right) const;
};

example example::operator + (int right) const
{
    example temp;
    temp.seta(a + right);
    return temp;
}

Or:

// as a global operator:

class example
{
    ...
public:
    ...
    friend example operator + (const example& left, int right);
};

example operator + (const example& left, int right)
{
    example temp;
    temp.seta(left.a + right);
    return temp;
}

If you had defined a contructor that takes an int as input, the compiler could have created a temp example when you pass an int value to the example::operator+(const example&) method, eg:

class example
{
    ...
public:
    example (int f);
    ...
    example operator + (const example& right);
};

example::example::(int f)
    : a(f)
{
}

example example::operator + (const example& right)
{
    example temp;
    temp.a = a + right.a;
    return temp;
}

Likewise, t = 1 + r; means t = operator+(1, r); (since 1 is not a class type). It does not compile because you did not define a global + operator that takes an int on the left and an example on the right:

class example
{
    ...
public:
    ...
    friend example operator + (int left, const example& right);
};

example operator + (int left, const example& right)
{
    example temp;
    temp.a = left + right.a;
    return temp;
}


回答2:

If you rewrite the offending statement verbosely, it looks like:

t.operator=(1.operator+(r));

Which doesn't make a lot of sense and confuses the compiler.

Being confused, it can either convert the number 1 to an instance of example or convert the variable r to an integer. Unfortunately, you don't supply enough information in your class to do either.

If you provide a constructor for your class that takes an integer, things may come out less confusing:

class example
{
  public:
    example(int new_value) : a(new_value)
      { ; }
};

Now you have provided the compiler with a method convert integers into examples.

Another alternative is to provide a casting or conversion operator:

class example
{
  public:
    int operator int (const example& e)
    {
      return e.a;
    }
};

There are other alternatives, such as creating an addition method that takes an integer.

Edit 1:
If you are designing a units class beware of constants. You have no idea what unit the constant is in, such as feet or inches. The compiler won't be able to help, since numerical constants don't have units associated with them.



回答3:

It's really simple, when you overloading operator you can do it in two ways:

First is like you do it. You inserted overloaded operator for your class in it. This way the left argument must be the object of this class. Why? Because when you call this operator you can do it as call of every function in your class. You can't do it other way, because you can't call this function by other type.

Second, you made overloaded operator as friend to your class. In your class you put this line:

 friend example& operator + (const example &left, const example &right);

And after your class definition you put this:

example& operator + (const example &left, const example &right){...}

So if you want to add integer or other types you must just modify your operator to add it like this:

example& operator + (const example &left, const int right){...}

or this:

example& operator + (const int left, const example &right){...}

Choose one or both if you want to add int from left or rigth side of the opearator.