【问题标题】:dealing with assignment operator overloads; can you re-assign a reference?处理赋值运算符重载;您可以重新分配参考吗?
【发布时间】:2012-01-16 23:31:30
【问题描述】:

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

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

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

你如何解决这个问题?

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

【问题讨论】:

  • 旁注:如果您使用复制交换习语 (stackoverflow.com/questions/3279543/…),&rhs != this 检查是多余的。
  • @SirYakalot:请看我的编辑。我希望这可以为您澄清一些事情。

标签: c++ reference assignment-operator


【解决方案1】:

不,您不能重新安排参考。

考虑:

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 对象,每个对象都引用了一个不同的FooBar 有一个operator=,它执行以下操作:

foo_ = rhs.foo_;

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

【讨论】:

  • 这样您就可以为包含引用的类编写重载赋值运算符。初始化列表中引用的适当语法是什么?
  • @SirYakalot:只需obj::obj() : ref_(ref) {};
  • 哦,好吧。不过,有一个问题,这本质上是在说所指=本身,对吗?所以它是无害的,因为它什么都不做,但是当我错过这个列表时,为什么编译器会抱怨呢?
  • 让我澄清一下;我上面发布的代码可能有点混乱。语法是这样的:obj::obj(Thing&amp; that_other_ref) : my_ref_(that_other_ref) {} 其中my_ref_class obj 的成员,其类型为reference-to-something。
【解决方案2】:

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

【讨论】:

  • 没有办法为有引用的类写赋值运算符?
  • @SirYakalot:不。见我的帖子。
  • @SirYakalot:在我看来没有。
  • @SirYakalot:它似乎有效,因为它没有重新安装引用。它为推荐人分配了一个新的价值。但它并没有像你认为的那样工作。
【解决方案3】:

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

但代码是合法的,即使它没有按照您的想法执行。它不是重新绑定或重新分配引用,而是分配给所指对象(引用的目标)。

【讨论】:

  • 但这没关系吧?因为我们只是将原始对象设置为它自己,这没关系。或者这是否意味着副本仍然没有自己的参考?
  • 这取决于你想要什么行为。在许多情况下,分配所指对象是正确的行为。这两个对象仍然引用不同的内存位置,但内存位置中的值已从一个复制到另一个。
【解决方案4】:

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

myReference = rhs.myReference;

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

【讨论】:

    【解决方案5】:

    你可以用一个使用引用的类来做一个赋值运算符,但是这一行:

    myReference = rhs.myReference;
    

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

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

    【讨论】:

    • 因为您开始谈论原始指针而取消我的投票。他应该使用指针,而且很可能应该是智能指针。
    • @BenVoigt:只有当你指向的东西已经包含在智能指针中时,你才能使用智能指针,有时这不在你的控制之下。智能指针用于动态分配的对象,有时您需要引用非动态分配的对象。
    • 是的,但这并不意味着原始指针在这里绝对合适,这意味着它可能是。
    猜你喜欢
    • 2021-10-22
    • 2019-04-16
    • 2021-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-30
    • 2013-02-14
    • 2016-08-30
    相关资源
    最近更新 更多