views:

1353

answers:

4

Hi,

I'm trying to create an overridden operator function using both const parameters, but I can't figure out how to do it. Here is a simple example:

class Number
{
    Number()
    {
        value = 1;
    };

    inline Number operator + (const Number& n)
    {
        Number result;

        result.value = value + n.value;
        return result;
    }

    int value;
}

What I am trying to do here is pass in two arguments into the addition function that are both const and return the result without changing anything in the class:

const Number a = Number();
const Number b = Number();
Number c = a + b;

Is this possible and how would I go about doing this?

Thanks,

Dan

+1  A: 
class Number
{
    Number()
    {
        value = 1;
    };

    inline Number operator + (const Number& n) const
    {
        Number result;

        result = value + n.value;
        return result;
    }

    int value;
}
cletus
+1  A: 

How about:

inline Number operator + (const Number& n) const
Milan Babuškov
+7  A: 

inline is understood in class declarations so you don't need to specify it.

Most idiomatically, you would make operator+ a non-member function declared outside the class definition, like this:

Number operator+( const Number& left, const Number& right );

You might need to make it a friend of the class if it needs access to Number's internals.

If you have to have it as a member function then you need to make the function itself const:

Number operator+( const Number& n ) const
{ // ...

For classes like Number, operator+ is typically implemented in terms of operator+= as usually you want all the usual operators to work as expected and operator+= is typically easier to implement and operator+ tends not to lose any efficiency over implementing it separately.

Inside the class:

Number& operator+=( const Number& n );

Outside the class:

Number operator+( const Number& left, const Number& right )
{
    return Number( left ) += right;
}

or even:

Number operator+( Number left, const Number& right )
{
    return left += right;
}
Charles Bailey
Shouldn't you be copying "left" and modifying the copy in your implementation of operator+?
Steve Jessop
i'm not sure whether that matters much though. It could if Number has a private copy constructor or could throw (in which case operator+ could catch it). it also could slice from a derived class (and as a result, we would loose any polymorphism we might need). but i think that's not the case here.
Johannes Schaub - litb
Sorry, I just misread the code: of course he is copying "left" in the pass-by-value. For some reason I read it as Number -)
Steve Jessop
If you're implementing an operator+ then it implies that you want a new object. It really only makes sense for objects with value semantics so slicing shouldn't really be an issue. If it is an issue you probably don't want to implement something with the semantics of a typical operator+.
Charles Bailey
+1  A: 

While I feel the previous answers are good enough, I believe some clarification is needed.

Operators come (usually) in two flavors

The first being the non-member functions, the second being the member function whose parameter is the "right operand" of the operation and which usually returns the current modified object.

For example, imagine there's an operator "§" for a class T. It could be written either as a non-member function:

T operator § (const T & lhs, const T & rhs)
{
   T result ;
   // do the lhs § rhs operation, and puts the result into "result"
   return result ;
}

or as a member function:

T & T::operator § (const T & rhs)
{
   // do the "this § rhs" operation, and puts the result into "this"
   return *this ;
}

or even (very unusually) as another member function:

T T::operator § (const T & rhs) const
{
   T result ;
   // do the "this § rhs" operation, and puts the result into "result"
   return result ;
}

Usually, you should prefer the non-member function, if only because you should not declare it friend. Thus, using non-member non-friend function enhance the encapsulation of your object.

Disclaimer: There are other flavors, but I'm limiting myself to arithmetic operators like +, *, / -, etc., here, as well as "credible" operator prototypes.

Analyse your use of the operator

In the case of "+":

  1. each operand needs to be constant because a = b + c must not change b, nor c.
  2. you can accumulate "+", like in a = b + c + d + e, so temporaries must exist.

    T operator § (const T & lhs, const T & rhs) { T result ; // do the lhs § rhs operation, and puts the result into "result" return result ; }

In the case of "+=":

  1. You know the left operand A (from A += B) will be modified
  2. You know the left operand A (from A += B) is its own result

So you should use:

T & T::operator += (const T & rhs)
{
   // do the "this § rhs" operation, and puts the result into "this"
   return *this ;
}

As always, premature optimization is the root of all evil

I've seen this kind of code in production code so, it does happen:

T & operator + (const T & lhs, const T & rhs)
{
   static T result ; // result is STATIC !!!!
   // do the lhs + rhs operation, and puts the result into "result"
   return result ;
}

The author hoped to economize one temporary. With this kind of code, writing "a = b + c + d" leads to interesting (and wrong) results.

^_^

Last but not least

I did write a list of operator overloading prototypes in the following page http://www.augias.org/paercebal/tech_doc/doc.en/cpp.basic.operator_overloading_prototype.html

The page is still on construction, but its main use (easy to copy/paste working prototypes) can be quite useful...

paercebal