1

I'm new to C++ and I'm starting with learncpp website. In Assignment Operator Overloading chapter has those lines of code:

Fraction& Fraction::operator= (const Fraction &fraction)
{
    m_numerator = fraction.m_numerator;
    m_denominator = fraction.m_denominator;
    return *this;
}

The first thing is why overloading assignment have to return reference instead of value?

And second thing is since this is a pointer itself then *this will be represented as dereference so its value should be object, but return value of assignment operator is Fraction&. Do I have a misunderstanding here?

alseether
  • 1,889
  • 2
  • 24
  • 39
sasorihuriko
  • 199
  • 1
  • 9
  • Note: `*this` is lvalue – Chen Li Nov 24 '17 at 15:04
  • As you ask for mis-understanding: There are multiple meanings of `&` which are precisely distinguished by the compiler but no everytimes by the human readers/writers: (in declarators) `&` after a type modifies the type to a reference to this type (similar like `*` for pointers), (in expressions) `&` before an expression as address operator, not to forget the `&` between expressions which denotes "bitwise and". – Scheff's Cat Nov 24 '17 at 15:10
  • "Note that the supplied argument is the right side of the expression. The operator returns the object to preserve the behavior of the assignment operator, which returns the value of the left side after the assignment is complete." This allows chained assignment (as pointed in answer below). - https://msdn.microsoft.com/en-us/library/7ac5szsk.aspx – SChepurin Nov 24 '17 at 15:33
  • The linked duplicate has a large _large_ amount of information in it, happy reading I suppose – Passer By Nov 24 '17 at 18:11

3 Answers3

6

A pointer is a data type that holds a memory address of the type the pointer points to, or nullptr if it doesn't refer to anything. (Or a dangling pointer, or a garbage value... but that's a bad place.)

So dereferencing a pointer by *this means that you are now dealing with the object pointed to by the pointer. Which is why this->foo and (*this).foo do the same thing.

Why does C++ have a this pointer, rather than (say) a self reference? That's just how C++ evolved, which Bjarne Stroustrup discusses at length in his excellent book The Design and Evolution of C++.

Back to your operator= situation. In C++, you can typically do this kind of construct: x = y = z;, which is ordered like x = (y = z); due to the right-to-left association of assignment.

If your assignment was void operator=(Fraction const&) then it could not be used to do assignment chaining. Not supporting assignment chaining would be "friction" for anyone used to the expected behavior of assignment and how C++ built-in types allow chaining.

Why return Fraction& versus Fraction object, is more than a simple performance optimization. Because if you did (x = y).negate(); the hypothetical negate method would be operating on a temporary rather than on x.

Eljay
  • 4,648
  • 3
  • 16
  • 27
  • i mean return value of `operator=(Fraction const&)` is Fraction& which is reference but it returns `*this` (represented as object) – sasorihuriko Nov 24 '17 at 15:16
  • `*this` is required when member function with ref-qualifier – Chen Li Nov 24 '17 at 15:18
  • A reference is an alias for the object. So in this situation a `Fraction&` is an alias for `*this` object. (How the magic of a reference is done under the covers is an implementation detail. My platform does it as a pointer, but the pointer-ness is not manipulable in C++.) – Eljay Nov 24 '17 at 15:23
  • 1
    `this` is a pointer because C++ had `this` before it had references. http://www.stroustrup.com/bs_faq2.html#this – Christian Hackl Nov 24 '17 at 19:10
3

why overloading assignment have to return reference instead of value?

Well, consider the semantics of assignment.

X a(0);
X b(42);

a = b;

should the last line create a new temporary X object? I can't think why you'd want it to, but that would be the effect of operator= returning a value.

So why does it return a reference at all? Because built-in types have these assignment semantics:

ssize_t rc;
if ((rc = write(fd, buf, sz)) != sz) {
    // handle error
}

that is, you can use the value of an assignment expression in an outer expression. The value is the same as the value of the left-hand-side after the assignment. How do you get the same behaviour for user-defined types?

For a motivating example, consider

std::vector<int> v;
if ((v = make_huge_vector()).empty()) {
  // it's not supposed to be empty
}

Would it be reasonable for this to create a redundant temporary copy of the (hopefully) massive vector?

"*this" will be represented as dereference

When you dereference a pointer-to-object, you get a reference to the object. Otherwise, again, dereferencing a pointer would have to create a temporary copy of the object. Consider:

X *x = new X;
x->init();

is the same as

(*x).init();

should we be initializing a copy of the object pointed to by x? We'd never be able to initialize the allocated object. So, the only sane thing for (*x) to evaluate to, is a reference to the object.

Useless
  • 64,155
  • 6
  • 88
  • 132
1

It returns a reference so you can perform further actions on the object after assigning to it:

struct A {
  void doSomething();
  A& operator=(const A&);
};
A a;
A b;
(a = b).doSomething();

If the assignment operator returned by value then you would call doSomething() on the unnamed temporary object, instead of on a. That would not be useful.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521