处理赋值运算符重载;您可以重新分配引用吗?

dealing with assignment operator overloads; can you re-assign a reference?

本文关键字:分配 引用 新分配 重载 赋值运算符 处理      更新时间:2023-10-16

如果你的类有一个引用变量,那么需要编写重载赋值运算符。

我的印象是,您只能在实例化时设置一次引用,因此不能执行以下操作:

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

你如何解决这个问题?

编辑 - 好的,所以我被告知你不能在带有引用的类上使用赋值运算符,很好。但是为什么视觉工作室让我这样做呢?程序运行和一切。

不可以,您不能重新拔插参考。

考虑:

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

编译器如何知道您正在尝试重新拔插ar以引用b,而不是将a的值设置为43

您可以使用指针而不是引用来解决此"问题"。

编辑

:根据您的编辑,

好的,所以我被告知您不能在具有 参考,很好。但是为什么视觉工作室让我这样做呢?这 程序运行和一切。

你结论的前提是错误的。 可以在包含引用的类上使用赋值运算符。 您不能做的是重新拔插参考。 如上面的代码所示,如果您尝试使用 ar = a; 重新分配引用,则不会重新放置ar引用的内容,而是更改ar引用的值。

Visual Studio"让你做到",没有困难。 误解正是Visual Studio让你做的。 它不允许您重新拔插参考。 它允许您更改引用的值。 这里有一个例子,我希望能澄清这意味着什么。

#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();
}

上面的代码建立了 2 个Foo对象(foo1foo2 (,并创建了 2 个Bar对象,每个对象都有对不同Foo的引用。 Bar有一个operator=,它执行以下命令:

foo_ = rhs.foo_;

如果C++允许您以这种方式重新拔插引用,foo_现在将引用 Foo 的不同实例。 但是,事实并非如此。 这不会改变foo_所指的内容。 相反,它会在Foo本身上调用operator=。 运行上面的代码,您将看到bar2Foo的地址永远不会更改。 如果可以重新拔插引用,它就会改变。

您可以使用使用引用的类创建赋值运算符,但以下行:

myReference = rhs.myReference;

不重新指派引用。 如果重新分配引用所引用的内容。 因此,在该赋值之后,myReference 和 rhs.myReference 现在不再引用同一个对象。 但是他们所指的事物现在具有等效的值(或该类型的任何赋值(。

如果需要可重新分配的引用,请使用指针。 这就是他们的目的。 事实上,在现代C++中,这几乎是原始指针的唯一用途。 如果你引用的对象是动态分配的,那么你应该把它放在一个shared_ptr中,并使myReference成为另一个shared_ptr,或者一个weak_ptr

用两个词来说 - 你不能。引用具有实际对象的语义,因此赋值运算符实际上将调用基础对象的赋值,而不是引用本身。

引用不能反弹。 (好吧,放置new可以,但不要那样做!

但是代码是合法的,即使它没有做你认为它做的事情。 它不是重新绑定或重新分配引用,而是分配给引用对象(引用的目标(。

您的代码按编写的方式工作,但是您不会重新分配引用。

myReference = rhs.myReference;

将 rhs.myReference 引用的对象分配给 myReference。因此,假设赋值之前&myReference != &(rhs.myReference)为真,则赋值后仍为真,但是这些地址上的对象将包含相同的值(因此myReference == rhs.myReference如果operator==是为类型定义的并且以非意外的方式工作(。重新分配引用(这是不可能的(意味着在分配之后&myReference == &(rhs.myReference)为真。所以真正的问题是你想做什么:你是想将rhs.myReference引用的对象复制到this->myReference引用的对象中(在这种情况下,你的代码很好(,还是想this->myReference引用与rhs.myReference相同的对象(这在引用中是不可能的, 所以你需要使用指针(。