views:

274

answers:

7

Hi,

I'm not sure if

return *this

is the only way we could return an instance of a class who called a member function? Reason why I asked is because our instructor told us to avoid using pointers if necessary and I'm wondering if this is a case where the only necessary way to do it is by returning the this pointer.

I'm working with a fraction class that holds private data members numerator and denominator. The member function I'm talking about is used to add two fractions for example:

Fraction C = A.plus(B);

plus member function is defined as this:

Fraction& plus( const Fraction frac )

EDIT:

The instructor wants us to do C = A += B .. so I guess that's why..

Thanks for the clear and helpful answers BTW

+1  A: 

Yes, this is the only way. The only way to access the current object in a method is via this, and it is a pointer.

It is fine, and is an accepted practice.

Michael
+1  A: 

There's nothing wrong with returning *this. For example, that's how overloads of modifying operators are supposed to work. It seems like the plus method is really just a way of providing an operator+= for your class without actually overloading the operator (I assume you haven't gotten to operator overloading yet), so returning *this in this case is the usual behavior.

Tyler McHenry
A: 

In your plus() method you should probably create a new Fraction object and return that, instead of modifying the current one and then returning *this. You probably don't want to change A in A.plus(B). To return a new Fraction, the signature of plus() would best be:

Fraction plus(const Fraction &frac);

(In case you're not currently modifying this in the plus() method, why do you want to return *this?)

sth
+3  A: 

I think in this case it is safe to use

return *this

because this refers to the current object so it is guaranteed to exist, so it won't be null.

The reason plus returns reference to itself is so that it can be chained:

Fraction C = A.plus(B).plus(D) // perhaps?

Note that in the above case C will be created by copying the result of addition. This also assumes that operation plus is meant to modify object (in this case A) and return the reference to this modified object.

Wouldn't plus accept reference instead of making copy of the parameter?

Fraction& plus( const Fraction& frac )

This is similar to how you would implement operator= (an example):

  A& operator=(const A& right) {
    if(this == &right) return *this;    // Handle self-assignment
    b = right.b;
    return *this;
  }

Maybe you would want to not modify object and return new object:

// assuming there's a constructor Fraction(int numerator, int denominator):
Fraction* plus(Fraction const& rhs)
{
    return new Fraction(numerator * rhs.denominator
                        + rhs.numerator * denominator,
                        denominator * rhs.denominator);
}

But this of course has to return pointer to new instance which is not a reference as maybe required in your task (?).

Or even better:

Fraction plus(Fraction const& rhs)
{
    return Fraction(numerator * rhs.denominator
                    + rhs.numerator * denominator,
                    denominator * rhs.denominator);
}

This will create Fraction in the space of calling function so there's no overhead of copying structure on return.

stefanB
Actually, this is not guaranteed to be non-null. Calling a method on a NULL object will result in a crash when this is dereferenced.
Michael
But in that case you would get crash when trying to call plus on NULL not inside plus when you try to return *this I assume
stefanB
You'd only crash on the call if the function is virtual, since it would try to access the vtable. Otherwise it is like calling a non-member function with an invalid parameter.
Michael
You could have a dangling reference (if you deleted object that the reference was aliasing) but that is different kind of problem. You could try passing a reference from pointer where pointer points to 'null' object but you would need to dereference it to get object reference so you would crash there. I don't see a scenario where you would get an issue with return *this when you pass reference to a method - but if you have example I'm happy to learn.
stefanB
Fraction* foo = NULL;foo->plus(...)Obviously contrived, but you could imagine other situations using an uninitialized object.return *this will access the copy constructor that will most likely access members of the object, resulting in a NULL reference.
Michael
You're right, but I guess you're trading between checking pointer for null before calling a method on it and checking inside a method if we were called on null pointer ... we would have to write every method as if (!this) return (can't really return reference so make a new object return reference to it a leak memory?).
stefanB
@Michael: Calling a method on NULL may not crash on your computer. But I believe (haven't checked the standard personally) that something like this should fall under "undefined behavior".
newacct
@newacct - Correct, my descriptions are based on what should happen with most compilers. But the standard leaves this as undefined behavior.
Michael
@Michael: but you might as well say that it's not guaranteed to be non-null even for a virtual function, because someone might stop the program in the debugger after the function is called, and modify "this" to be NULL. If someone uses your function in an invalid way, they get undefined behaviour. It's not your problem what that behaviour is. If the rest of the program is valid, then "this" is not NULL, and that's as "guaranteed" as anything ever can be in C++.
Steve Jessop
"If the rest of the program is valid" and everything it does yields behaviour that is defined, I should say, since "valid program" is a technical term.
Steve Jessop
A: 

I believe that the semantics should be that the member function 'plus' returns a 'new' object which represents the sum of the caller and the called. note :: new does not mean 'new' keyword in C++ :) so for your example,

// the constructor accepts (numerator, denominator).
// in your case, the caller object would be A, and the called object would be B(other).
return Fraction(numerator * other.denominator + other.numerator * denominator, denominator * other.denominator);

The only place I see it correct to return a reference to this is when you overload operators that have side effects.

To clarify more, this should be your 'plus' signature,

Fraction plus( const Fraction& frac );

neither the caller nor the called should be effected by the 'plus'.

AraK
+6  A: 

Get a new instructor. It looks as if the declaration of plus() is completely wrong.

  • it probably should return a value rather than a reference
  • if it must return a reference, it should return a const reference
  • it should definitely take a const reference as a parameter

That is for likely sensible implementations of a member plus() function. Of course, it should probably be a friend.

anon
you are reading my mind in your first point :D
AraK
I think this is more likely a bad student copying the question incorrectly that a bad teacher. I would argue prefer reference to a pointer. And the return is returning a reference not a pointer as retested by the teacher.
Martin York
A: 

our instructor told us to avoid using pointers if necessary

You're actually returning the value of dereferencing a pointer, not the pointer. So you should be good.

Personally, I never explicitly call methods or refer to members via this. That is, I DO NOT do the following:

class A {
    public:
    int x;
    int get_x()
    {
        return this->x;
    }

    int get_x_plus_5()
    {
        return this->get_x() + 5;
    }
}

However, I am perfectly fine with returning *this.

Your instructor probably is trying to get you to avoid (1) returning pointers to objects on the stack from functions (which means that they won't exist after the function exits) and (2) allocating objects on the free store when you don't have to. this doesn't suffer from either of those issues.

Max Lybbert