1

I wanted to ask a question about operator overloading in C++.

I am a beginner in C++ and have been learning OOP.

Consider the following overloaded copy assignment operator:

class Base {
private:
    int value;
public:
    Base () : value {0} 
    {
        cout << "Base No-args constructor" << endl; 
    }
    Base (int x) : value {x} {
        cout << "Base (int) overloaded constructor" << endl;
    }
    Base (const Base &other) : value {other.value} {
        cout << "Base copy constructor" << endl;
    }
    Base & operator = (const Base &rhs) {
        cout << "Base operator=" << endl;
        if (this == &rhs)
            return *this;
        value = rhs.value;
        return *this;
    }

    ~ Base () {cout << "Base Destructor" << endl;}
};

I wanted to clarify two points.

  1. How does this copy assignment operator work?
  2. Does the reference before the operator keyword need a parameter name?

I wanted to give my interpretation on (1).

If I have the following code in my main():

Base b {100}; // overloaded constructor
Base b1 {b}; // copy constructor
b = b1; // copy assignment

What I think happens is that the no args constructor is called for a1, evidently because no arguments are passed into the construction of the object. When a2 is initialised, a temporary copy of a1 is made and then the operator is evaluated with respect to the Base class, hence the Base overloaded copy assignment block is run, and the a1 object is returned via return *this to the reference a2.

To explain my thoughts on the second question,

I thought that all parameters need a name when a function or method is declared (I may of course be wrong).

If my overloaded copy assignment block was written hypothetically as:

Base &lhs operator = (const Base &rhs)

am I right in saying that lhs is referring to a2 but as we don't do anything with lhs due to the implied this parameter, we don't need to give a parameter name following the ampersand before the operator?

bodn19888
  • 167
  • 10

1 Answers1

1

How does this copy assignment operator work?

Redacted:

Base& operator=(Base const& rhs) {
    cout << "Base operator=\n";
    value = rhs.value;
    return *this;
}

The assignment operator is just a function call. In this particular class's case, the compiler will synthesize one that does the right thing, but if you want the cout side-effect for educational purposes you've done the right thing.

You could also call it in a method function style:

b.operator=(b1);

The b = b1; is just syntactic sugar for the above.

The assignment operator should be self-assignment safe. But general guidance is to make it safe without checking for the self-assignment case explicitly, which is "bad" because it optimizes for the pathological case.

In your implementation, it is safe without the self-assignment check.

I prefer specifying the qualifier in Base const& order rather than const Base& order, because the general rule is "the qualifier always binds to the thing to its immediate left", and the exception to the general rule is "...unless the qualifier comes first, in which case it then binds to the thing to its immediate right." That becomes a problem when people have the grasped the exception to the rule, but not the general rule, and then have troubles parsing Base*const* in their heads.

Does the reference before the operator keyword need a parameter name?

It's name is *this. It is a return type, not a parameter, so it does not have a parameter name.

Some people have troubles with "Why does C++ use this as a pointer to itself, rather than as a reference to itself."

It is a historical anomaly from the evolution of C++. Originally, there was a this pointer, and references had not been added to the language yet.

With 20/20 hindsight, this would have been a reference. But that ship has sailed.

In my own code, only to help make it more legible, I'll do:

auto& self = *this;
self[i] = 5;

...rather than the more confusing (imo)...

(*this)[i] = 5;
Eljay
  • 4,648
  • 3
  • 16
  • 27
  • when you say "it's name is `*this`. It is a return type", the ampersand `&` denotes that the return type is of an `l-value` type, if I'm not mistaken i.e. that it has a position in memory, which is the object that we return, `*this`? My original thought was that by denoting `&` as the return type, it would mean that the return type is a reference, but we are returning the object itself via `return *this`, right? – bodn19888 Aug 15 '20 at 14:32
  • @bodn19888 • correct, it returns a _reference_ to itself, it allows chaining `b = b1 = b2;` I'm not a fan of chaining, but `void operator=(Base const&)` would not be idiomatic C++, which would make my coworkers grumpy. So I follow the idiomatic conventions. – Eljay Aug 15 '20 at 14:35
  • oh right I just checked cpp references and they say *The keyword `this` is a `prvalue` expression whose value is the address of the implicit object parameter* so in Leyman's terms `this` is just a pointer to the reference of the object itself? God C++ can be so bloody tough sometimes for a beginner. – bodn19888 Aug 15 '20 at 14:41
  • 2
    Note that in C++ a reference is an _alias_ ... another name for the same object; other languages like Java or C# use the term "reference" in a different sense. C++ does have a rather daunting learning curve, I suggest one of the [good C++ books](https://stackoverflow.com/a/388282/4641116) to learn from. – Eljay Aug 15 '20 at 14:42
  • ahhhhhhhh @Eljay by using `this` in the return, the `this` itself is the reference to the object because it's an alias. Yeah now I understand thanks!! – bodn19888 Aug 15 '20 at 14:52