0

If your class has a reference variable, then your overloaded assignment operator needs to be written.

I was under the impression that you could only set a reference once on instantiation and therefore cannot do something like:

MyClass& MyClass::operator=(const MyClass& rhs) 
{
    if (&rhs != this)
    {
        myReference = rhs.myReference;
    }
    return *this;
}

How do you solve this problem?

EDIT - OK so I'm told you cannot use an assignment operator on a class with a reference, fine. But then why does visual studio let me do it? The program runs and everything.

Dollarslice
  • 9,917
  • 22
  • 59
  • 87

5 Answers5

1

You can make an assignment operator with a class that uses a reference, but this line:

myReference = rhs.myReference;

Does not reassign the reference. If reassigns the thing that the reference is referring to. So, after that assignment, myReference and rhs.myReference do not now refer to the same object. But the things that they refer to now have equivalent values(or whatever assignment means for that type).

If you need a reassignable reference, use a pointer. That's what they're for. In fact, in modern C++, that's pretty much the only use left for a raw pointer. If the object you're referring to is dynamically allocated, then you should put it in a shared_ptr, and make myReference either another shared_ptr, or a weak_ptr.

Benjamin Lindley
  • 101,917
  • 9
  • 204
  • 274
  • Taking away my upvote because you started talking about raw pointers. He should use a pointer, and chances are it should be a smart pointer. – Ben Voigt Dec 09 '11 at 17:44
  • @BenVoigt: You can only use a smart pointer if the thing you are pointing at is already contained in a smart pointer, and sometimes that's not under your control. Smart pointers are for dynamically allocated objects, and sometimes you need references to things that aren't dynamically allocated. – Benjamin Lindley Dec 09 '11 at 17:46
  • True, but that doesn't mean that a raw pointer definitely IS appropriate here, it means it might be. – Ben Voigt Dec 09 '11 at 17:57
1

No, you cannot re-seat a reference.

Consider:

int a = 42, b = 43;
int &ar = a;
ar = b;

How can the compiler know that you are trying to reseat ar to refer to b, and not set the value of a to 43?

You solve this "problem" by using a pointer, not a reference.

EDIT: Per your edit,

OK so I'm told you cannot use an assignment operator on a class with a reference, fine. But then why does visual studio let me do it? The program runs and everything.

The premise of your conclusion is wrong. You can use an assignment operator on a class which contains a reference. What you cannot do is re-seat a reference. As demonstrated in my code above, if you try to reassign a reference using ar = a; you will not re-seat what ar refers to, but change the value of what ar refers to.

Visual Studio "lets you do it," without difficulty. The misunderstanding is exactly what Visual Studio is letting you do. It's not letting you re-seat the reference. It's letting you change the value of the referant. Here is an example that I hope will clarify what this means.

#include <iostream>
#include <string>
using namespace std;

class Foo
{
public:
    void dump() const
    {
        cout << "Foo instance " << showbase << this << "\n";
    }
};

class Bar
{
public:
    Bar(Foo& foo) : foo_(foo) {}
    Bar& operator=(const Bar& rhs) 
    {
        foo_ = rhs.foo_;
        return * this;
    }

    void dump() const
    {
        cout << showbase << "Bar instance " << this << "\t";
        foo_.dump();
    }

private:
    Foo& foo_;
};

int main()
{
    cout << "foo1: ";
    Foo foo1;
    foo1.dump();

    cout << "foo2: ";
    Foo foo2;
    foo2.dump();

    cout << "bar1 :";
    Bar bar1(foo1);
    bar1.dump();

    cout << "bar2 :";
    Bar bar2(foo2);
    bar2.dump();

    bar2 = bar1;
    cout << "bar2 after assign :";
    bar2.dump();
}

The code above establishes 2 Foo objects (foo1 and foo2) and creates 2 Bar objects, each of which has a reference to a different Foo. Bar has an operator=, which executes the following:

foo_ = rhs.foo_;

If C++ allowed you to re-seat references in this way, foo_ would now refer to a different instance of Foo. But, it doesn't. This doesn't change what foo_ refers to. Instead, it calls operator= on the Foo itself. Run the above code and you'll see that the address of the Foo in bar2 never changes. If you could re-seat references, it would change.

John Dibling
  • 99,718
  • 31
  • 186
  • 324
  • so you CAN write an overloaded assignment operator for classes that contain references. what's the appropriate syntax for the reference in the initialiser list? – Dollarslice Dec 22 '11 at 16:56
  • @SirYakalot: Simply `obj::obj() : ref_(ref) {};` – John Dibling Dec 22 '11 at 16:59
  • oh right ok. one question though, this is essentially saying referent = itself, right? So it's harmless because it does nothing, but then why does the compiler complain when I miss this out of the list? – Dollarslice Dec 22 '11 at 17:37
  • Let me clarify a bit; the code I posted above may be a bit confusing. The syntax is this: `obj::obj(Thing& that_other_ref) : my_ref_(that_other_ref) {}` where `my_ref_` is a member of `class obj` that is of type reference-to-something. – John Dibling Dec 22 '11 at 18:26
0

In two words - you can't. References have semantics of an actual object, so assignment operator will actually call an assignment for underlying object and not the reference itself.

Violet Giraffe
  • 32,368
  • 48
  • 194
  • 335
0

References can't be rebound. (Well, placement new can, but DON'T DO THAT!)

But the code is legal, even though it doesn't do what you think it does. It isn't rebinding or reassigning the reference, rather assigning to the referent (the target of the reference).

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • but that's fine right? because we're just setting the original object to be itself, which is OK. or does that mean the copy is still without its own reference? – Dollarslice Dec 09 '11 at 17:54
  • It depends on what behavior you want. In many cases, assigning the referent is the correct behavior. The two objects still refer to different memory locations, but the value in the memory locations has been copied from one to the other. – Ben Voigt Dec 09 '11 at 17:58
0

Your code works as written, however you are not reassigning the reference.

myReference = rhs.myReference;

Will assign the object referenced by rhs.myReference to myReference. Therefore assuming that before the assignment &myReference != &(rhs.myReference) was true, it will still be true after the assignment, however the objects at those addresses will contain the same values (so myReference == rhs.myReference if operator== is defined for the type and works in a lets say nonsuprising way). Reassigning the reference (which is impossible) would mean that after the assignment &myReference == &(rhs.myReference) would be true. So the real question is what you want to do: Do you want to copy the object referred by rhs.myReference into the one referred by this->myReference (in which case your code is fine), or do you want to make this->myReference refer to the same object as rhs.myReference (which is not possible with references, so you would need to use pointers).

Grizzly
  • 19,595
  • 4
  • 60
  • 78