繁体   English   中英

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

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

如果您的类具有参考变量,则需要编写重载的赋值运算符。

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

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

你怎么解决这个问题?

编辑-好的,所以我被告知您不能在带有引用的类上使用赋值运算符,很好。 但是为什么Visual Studio让我这样做呢? 该程序运行,一切正常。

不,您不能重新放置参考。

考虑:

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

编译器怎样才能知道你正在尝试重新安装arb ,和没有设置a43

您可以通过使用指针而不是引用来解决此“问题”。

编辑:根据您的编辑,

好的,所以我被告知您不能在带有引用的类上使用赋值运算符,很好。 但是为什么Visual Studio让我这样做呢? 该程序运行,一切正常。

结论的前提是错误的。 可以在包含引用的类上使用赋值运算符。 您不能做的是重新放置参考。 如上面的代码所示,如​​果您尝试使用ar = a;重新分配引用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_所指的内容。 相反,它在Foo本身上调用operator= 运行上面的代码,您将看到bar2 Foo的地址永远不变。 如果您可以重新放置参考,它将改变。

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

myReference = rhs.myReference;

不重新分配参考。 如果重新分配引用所指的东西。 因此,在分配之后,myReference和rhs.myReference现在不再引用同一对象。 但是他们现在所指的事物具有相等的值(或该类型的任何赋值方式)。

如果需要可重新分配的引用,请使用指针。 那就是他们的目的。 实际上,在现代C ++中,这几乎是原始指针剩下的唯一用途。 如果您要引用的对象是动态分配的,则应将其放在shared_ptr ,并使myReference成为另一个shared_ptrweak_ptr

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

参考不能反弹。 (嗯,可以放置new ,但是不要那样做!)

但是该代码是合法的,即使它没有执行您认为的操作。 它不是重新绑定或重新分配引用,而是分配给引用对象(引用的目标)。

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

myReference = rhs.myReference;

将rhs.myReference引用的对象分配给myReference。 因此,假设在分配&myReference != &(rhs.myReference)为true之前,分配之后仍为true,但是这些地址处的对象将包含相同的值(因此,如果operator==myReference == rhs.myReference是为该类型定义的,并且可以说是一种非惊奇的方式)。 重新分配引用(这是不可能的)意味着分配后&myReference == &(rhs.myReference)将为true。 所以真正的问题是你想要做什么:你想通过复制引用的对象rhs.myReference成提到了一个this->myReference (在这种情况下,你的代码是罚款),或做你想this->myReference指向同一个对象rhs.myReference (这是不可能的引用,所以你需要使用指针)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM