Home > Software design >  Different order of adding same type objects causes an error
Different order of adding same type objects causes an error

Time:04-08

Could anyone explain why adding three objects like this a (a a) causes problems while a a a and (a a) a does not? The Foo class has one attribute num. Adding two Foo objects returns one with sum of their num values. Here is my code.

main.cpp

#include <iostream>
#include "Foo.h"
using namespace std;

int main()
{
    Foo a(4), b;
    b = a   a   a; // works fine
    cout << a.getNum() << " " << b.getNum() << endl; // outputs "4 12" as it should
    b = a   (a   a); // this one causes an error
    cout << a.getNum() << " " << b.getNum() << endl;
    return 0;
}

Foo.h

#ifndef FOO_H
#define FOO_H


class Foo
{
    public:
        Foo();
        Foo(int a);
        Foo operator (Foo& other);
        int getNum();

    protected:

    private:
        int num;
};

#endif // FOO_H

Foo.cpp


Foo::Foo()
{
    num = 0;
}

Foo::Foo(int a)
{
    num = a;
}

Foo Foo::operator (Foo& other)
{
    Foo tmp = (*this);
    tmp.num  = other.num;
    return tmp;
}

int Foo::getNum()
{
    return num;
}

The error message says error: no match for 'operator ' (operand types are 'Foo' and 'Foo') even though the operator is overloaded for Foo-type operands.

CodePudding user response:

All right, I got it. The only thing that I had to change was to add const in Foo.h

Foo operator (const Foo& other);

and in Foo.cpp

Foo Foo::operator (const Foo& other)
{
    Foo tmp = (*this);
    tmp.num  = other.num;
    return tmp;
}

Thanks.

CodePudding user response:

The expression (a a) yields a prvalue of type Foo. The only possible reference parameter types this kind of value can be assigned to are Foo&& or Foo const&. The reason why (a a) a (or the equivalent using no brackets) works is the fact that non-const functions can be invoked on prvalues.

I recommend going with the const version in this case, but you should also mark the operator const:

class Foo
{
    ...
    Foo operator (Foo const& other) const;
};

Foo Foo::operator (Foo const& other) const
{
    return num   other.num;
}

Probably preferrable would be to implement the operator at namespace scope which would allow you to apply the implicit conversion from int to Foo on both sides of :

class Foo
{
    ...
    friend Foo operator (Foo const& s1, Foo const& s2)
    {
        return s1.num   s2.num;
    }
    ...
};

Using this implementation not only

Foo c = a   1;

works, but also

Foo d = 1   a;
  • Related