Search code examples
c++computer-science

Why is returning an object reference using *this necessary in this case?


The course I am taking says that returning this object reference (using *this) is mainly for chaining equal signs (For example: b = d = c = a) However, I cannot understand how this return works while I am overloading the '=' operator. Is it also necessary if I am not going to use any kind of chain? How does this return statement works? Thank you very much.

class Rational {

    int _n = 0; // '_n' stands for numerator
    int _d = 1; // '_d' stands for denominator

public:

    Rational (int numerator = 0, int denominator = 1) : _n(numerator), _d(denominator) {};
    Rational (const Rational & rhs) : _n(rhs._n), _d(rhs._dd) {};

    ~Rational ();

    int numerator() const { retrun _n; };
    int denominator() const { return _d; };

    Rational & operator = (const Rational &);
    Rational operator + (const Rational &) const;
    Rational operator - (const Rational &) const;
    Rational operator * (const Rational &) const;
    Rational operator / (const Rational &) const;
};

Rational & Rational::operator = (const Rational & rhs) {
    if(this != &rhs){
        _n = rhs.numerator();
        _d = rhs.denominator();
    }
    return *this;
}

Rational Rational::operator + (const Rational & rhs) const {
    return Rational((_n * rhs._d) + (_d * rhs._n), (_d * rhs._d));
}

Rational Rational::operator - (const Rational & rhs) const {
    return Rational((_n * rhs._d) + (_d * rhs._n), (_d * rhs._d));
}

Rational Rational::operator * (const Rational & rhs) const {
    return Rational((_n * rhs._n), (_d * rhs._d));
}

Rational Rational::operator / (const Rational & rhs) const {
    return Rational((_n * rhs._d), (_d * rhs._n));
}

Rational::~Rational(){
    print("dtor: %d/%d\n", this->_n, this->_d);
    _n = 0; _d = 1;
}

std::ostream & operator << (std::ostream & o, const Rational & r){
    return o << r.numerator() << "/" << r.denominator();
}

int main(int argc, char** argv){

    Rational a = 7;                 // 7/1              
    cout << "a is: " << a << endl;
    Rational b(5, 3);               // 5/3
    cout << "b is: " << b << endl;
    Rational c = b;                 // Copy constructor
    cout << "c is: " << c << endl;
    Rational d;                     // Default constructor
    cout << "d is: " << d << endl;
    d = c;                          // Assignment constructor
    cout << "d is: " << d << endl;
    Rational & e = d;               // Reference
    d = e;                          // Assignment to self!
    cout << "e is: " << e << endl;

    cout << a << " + " << b << " = " << a + b << endl;
    cout << a << " - " << b << " = " << a - b << endl;
    cout << a << " * " << b << " = " << a * b << endl;
    cout << a << " / " << b << " = " << a / b << endl;

    return 0;
}

Solution

  • Let's say we make two Rational to demonstrate.

    Rational r1(1,2), r2(2,3);
    
    r1 = r2;
    

    When we do this, first r1 will be made equal to r2. Then the operation will return r1. Just like any function call we can choose to ignore the return value if we want.

    On the other hand we could also choose to not ignore it.

    Rational r1(1,2), r2(2,3), r3;
    
    r3 = (r1 = r2);
    

    The parenthesis to emphasize the fact that first r1 = r2, that will return r1. Next r3 = r1.

    It is the same principle as if you where using functions.

    #include <iostream>
    
    int print(int x) {
        std::cout << x << std::endl;
        return x;
    }
    
    void increase(int x) {
        std::cout << x + 5 << std::endl;
    }
    
    int main() {
        print(5); // We can ignore the return value, and just print the number
    
        int x = print(7); // We can print the number and store the value in a variable
    
        increase(print(3));  // We can print the value and pass it on to the increase function
    
        return 0;
    }