0

I was learning about this pointer that it contains the address of the current object that is invoking the function. But I have a doubt regarding this pointer when I am returning the current object from the member function.

#include<bits/stdc++.h>
using namespace std;
class Point
{
    private:
        int x,y;
    public:
        Point(int x,int y)
        {
            this->x = x;
            this->y = y;
            //cout<<this<<endl;                 
        }
        Point setX(int x)
        {
            this->x = x;
            //cout<<this<<endl;
            return *this;
        }
        
        Point setY(int y)
        {
            this->y = y;
            //cout<<this<<endl;
            return *this;
        }
        int getX()
        {
            return x;
        }                    
        int getY()
        {
            return y;
        }
};                                                           
int main()
{
    Point p(10,20);
    cout<<p.getX()<<" "<<p.getY()<<endl;
    p.setX(1000).setY(2000);
    cout<<p.getX()<<" "<<p.getY();
    return 0;
}

Why p.setX(1000).setY(2000) is only modifying the value of x, not y? Why in the second the cout statement answer is 1000 20 but it should be 1000 2000?

einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • 3
    `setX` and `setY` return their point _by value_, not by reference. That means that when you `return *this`, you return a copy of the object that you're calling the method on. – Nathan Pierson Aug 06 '21 at 05:16
  • You're returning the object _by value_, not _by reference_. `Point` contains a copy of `*this`. The return type should be `Point&` if you wish to chain your operations. – paddy Aug 06 '21 at 05:16
  • Note that typically setter-methods like `setX(int)` and `setY(int)` don't return anything at all, i.e. their return type would typically be `void`. Having them return a `Point` is legal C++, but it's going to confuse people. – Jeremy Friesner Aug 06 '21 at 05:19
  • @JeremyFriesner: Both styles of setters are in common use (and, frankly, I don't like either). – einpoklum Aug 06 '21 at 05:19
  • I would say that for something as ubiquitous and simple as 2D point, it seems a bit over-the-top to wrap this up in private data with getters and setters. Why not just make the members public and be done with it? – paddy Aug 06 '21 at 05:26
  • @Nathan Pierson That means each class functions have their own separate copy of the class object(which is invoking that function) and this pointer which holds the address of local function object. Please correct me if I am wrong? – Ajay kumar soni Aug 06 '21 at 11:28

2 Answers2

3

The reason is that your setX() and setY() methods return a Point - they return a copy of your object. So your setY() sets the y member of the temporary copy of your point, not of the original point.

You could rectify this by changing the signatures from:

Point setX(int x)

to:

Point& setX(int x)

and similarly for setY(). You'll note the return type is now Point& - a reference to a Point object.

Note, however, that your class' getter and setter method effectively allow treating x and y like public objects. So, unless you plan on potentially replacing them with some implicit representation of the coordinates (e.g. having angle + distance from the origin), in which case the setters and getters become interesting - you could also consider simplifying your class into:

struct Point { int x, y; }

the simple design is often appropriate.


Finally, unrelated to your specific question, your code starts with a few inopportune lines...

einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • But I have other doubts. Since this is a pointer then even if it is returning a copy of the current invoking object then also it should have changed the value of y also. – Ajay kumar soni Aug 06 '21 at 11:22
  • @Ajaykumarsoni: But you don't return `this`. You return `*this`, the dereferencing of `this`. Now, the type of `*this` is a `Point&`; but the return type is a `Point`, so a copy is made and returned. – einpoklum Aug 06 '21 at 12:12
  • Okay, now I got this. Since I am returning Point type then (*this) will create a local Point object and return it and then setY(2000) is called on this local object. And on this local returned object y value will get changed. Initially, I thought since I am returning (*this) from setX then setX will return the current calling object(p) from it. And then it will call setY on the same object. But rather setX will create a local object and then it will return. Correct me if I am wrong somewhere? – Ajay kumar soni Aug 06 '21 at 13:32
1

Because setX (and setY) returns by-value. In p.setX(1000).setY(2000);, p.setX(1000) returns a temporary Point (copied from *this) on which setY is invoked, any modifications from setY have nothing to do with p.

Change them to pass-by-reference.

Point& setX(int x)
//   ^
{
    this->x = x;
    //cout<<this<<endl;
    return *this;
}
    
Point& setY(int y)
//   ^
{
    this->y = y;
    //cout<<this<<endl;
    return *this;
}
songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • So you are saying p.setX(1000) is doing changes in its object copied from *this. Since it is changing the value in its local object copy then why changes are reflected back inside the p.x value. – Ajay kumar soni Aug 06 '21 at 11:44
  • @Ajaykumarsoni No, I'm saying `setY`. `p.setX(1000)` changed `p.x`, then it returned a copy, then `setY(2000)` is called on the copy, `y` of the copy is changed. The copy is destroyed immediately, left only `p.x` changed. – songyuanyao Aug 06 '21 at 13:06
  • Okay, now I got this. Since I am returning Point type then (*this) will create a local Point object and return it and then setY(2000) is called on this local object. And on this local returned object y value will get changed. Initially, I thought since I am returning (*this) from setX then setX will return the current calling object(p) from it. And then it will call setY on the same object. But rather setX will create a local object and then it will return. Correct me if I am wrong somewhere? – Ajay kumar soni Aug 06 '21 at 13:33
  • @Ajaykumarsoni You're correct. That's why changing to return-by-reference solves the issue; it makes `setX` returning the current object instead of a copy. – songyuanyao Aug 06 '21 at 13:43