Search code examples
c++chaining

chaining method of same object


I am working on the class right now

But there is a problem of chain of calling method(here is the code

class Point{
public:
    int x;
    int y;
    Point(int i , int j);
    Point incrementX();
    Point incrementY();
    void print();
};
Point::Point(int i, int j){
    x = i;
    y = j;
}
Point Point::incrementX(){
    x++;
    return(*this);
}
Point Point::incrementY(){
    y++;
    return(*this);
}
void Point::print(){
    cout << "(" << x << "," << y << ")" << endl;
}

void Q11(){
    Point a(2,3);
    //(3,4)
    a.incrementX().incrementY().print();
    //(3,3)why 33 here ??
    a.print();
}

I am confused why the last code a.print() gives the (3,3)

and I try to print out the address of this inside the method

I found the two address when calling incrementX() and incrementY() is different

My guessing is that incrementX() access to the class, but when calling incrementY() the class is occupied. So it make a copy of the class in the heap and then incrementY() change the y in the copy...

so the (3,4) is printed by copy, and (3,3) is printed by actual class...


Solution

  • Your incrementX and incrementY functions return by value. That is to say that upon return from those functions your object is copied and so subsequent operations occur on a different instance.

    You could see an error occur in compilation were you to delete the copy constructor. To do that add

    Point(const Point&) = delete;
    

    (assumes c++11 or greater to use delete. If older just make it private)

    So to diagnose your actual error:

    1. You construct the Point with values (2, 3).
    2. The first call to incrementX operates on your original instance (which is now value (3,3)) and passes out a copy on return.
    3. incrementY operates on the temporary copy and updates its value to (3, 4). It also returns a copy.
    4. You print the second temporary copy with the expected result (3,4).
    5. Now a.print() displays your original Point which has not been touched since the call to incrementX and that displays (3,3).

    In order to make use of the chaining you wish to use, all of your operations should occur on the same object and to achieve that you should return from those functions by non-const reference.

    The function signature

    Point Point::incrementX()
    

    becomes

    Point& Point::incrementX()
    

    and the complete code looks like.

    #include <iostream>
    using namespace std;
    
    class Point{
    public:
        int x;
        int y;
        Point(int i , int j);
        //Point(const Point&) = delete;
        Point& incrementX();
        Point& incrementY();
        void print();
    };
    Point::Point(int i, int j){
        x = i;
        y = j;
    }
    Point& Point::incrementX(){
        x++;
        return(*this);
    }
    Point& Point::incrementY(){
        y++;
        return(*this);
    }
    void Point::print(){
        cout << "(" << x << "," << y << ")" << endl;
    }
    
    int main(){
        Point a(2,3);
        a.incrementX().incrementY().print();
        a.print();
    }
    

    With the deleted copy constructor this code compiles fine, as no copies are happening.