0

As you know, we usually use the return by reference for the method chaining, I use the return by reference in the first code and the output is as I have predicted. In the second code block, when I did not use the return by reference, the chain was broken and my expected output was not generated, but in the third code block, I have reached the desired result using the chain method in continuation of the copy constructor / initialization in one declaration statements (without using return by reference), the question is, what is the logic behind the third code that protects the chain from breaking?

class Calc
{
private:
    int m_value;

public:
    Calc(int value = 0) : m_value{ value } {}

    Calc& add(int value) { m_value += value; return *this; }
    Calc& sub(int value) { m_value -= value; return *this; }
    Calc& mult(int value) { m_value *= value; return *this; }

    int getValue() { return m_value; }
};

int main()
{
    Calc calc;
    calc.add(5).sub(3).mult(4); // its OK and output 8

    std::cout << calc.getValue() << '\n';
    return 0;
}

class Calc
{
private:
    int m_value;

public:
    Calc(int value = 0) : m_value{ value } {}

    Calc add(int value) { m_value += value; return *this; }
    Calc sub(int value) { m_value -= value; return *this; }
    Calc mult(int value) { m_value *= value; return *this; }

    int getValue() { return m_value; }
};

int main()
{
    Calc calc;
    calc.add(5).sub(3).mult(4); // its NOT OK and output 5

    std::cout << calc.getValue() << '\n';
    return 0;
}

class Calc
{
private:
    int m_value;

public:
    Calc(int value = 0) : m_value{ value } {}

    Calc add(int value) { m_value += value; return *this; }
    Calc sub(int value) { m_value -= value; return *this; }
    Calc mult(int value) { m_value *= value; return *this; }

    int getValue() { return m_value; }
};

int main()
{
    Calc calc = Calc{0} // copy constructor / initialization
        .add(5) // method chaining
        .sub(3) // method chaining
        .mult(4); // method chaining, its OK and output 8

    std::cout << calc.getValue() << '\n';
    return 0;
}
  • You are assigning the result of the *last* function call (`.mult(4)`) to `calc`, all the other temporary objects are discarded – UnholySheep Jul 22 '18 at 11:52
  • Complementing UnholySheep's comment, it may become clearer if you parenthesize the expression: `Calc calc = ( ( ( Calc().add(5) ).sub(3) ).mult(4) );`. The difference lies in the assignment. – Rubens Jul 22 '18 at 12:05

1 Answers1

0

what is the logic behind the third code that protects the chain from breaking?

Chain does get break, but you use the final result to assign to calc

Calc calc = Calc{0}.add(5).sub(3).mult(4);

is equivalent to

Calc calc = Calc{2}.mult(4);

What ultimately gets copy constructed into calc is a temporary Calc object when multiplied by 4.

Gaurav Sehgal
  • 7,422
  • 2
  • 18
  • 34
  • Excellent, I got my answer. To make it clearer, in the third code block `Calc{0}` will create an anonymous `Calc` object, initialize it with the value 0, and then call its add method. then `Calc{0}.add(5)` return another anonymous `Calc` object and call its sub method and it continues until the last anonymous `Calc` object is assigned to `calc`. – Mohammad Ali Mansouri Khah Jul 23 '18 at 12:07