赋值运算符重载c ++的返回值

时间:2017-11-24 14:50:26

标签: c++ operator-overloading

我是C ++的新手,我从learncpp网站开始。 在赋值运算符重载章节中有这些代码行:

Fraction& Fraction::operator= (const Fraction &fraction)
{
    m_numerator = fraction.m_numerator;
    m_denominator = fraction.m_denominator;
    return *this;
}

首先,为什么重载赋值必须返回引用而不是值?

第二件事是因为this是一个指针本身,所以*this将被表示为取消引用,因此它的值应该是对象,但赋值运算符的返回值是Fraction&。我在这里有误会吗?

3 个答案:

答案 0 :(得分:4)

指针是一种数据类型,它包含指针所指向类型的内存地址,如果它没有引用任何内容,则为nullptr。 (或者悬挂指针,或垃圾值......但那是一个不好的地方。)

因此,通过*this取消引用指针意味着您现在正在处理指针指向的对象。这就是this->foo(*this).foo做同样事情的原因。

为什么C ++有一个this指针,而不是(比方说)一个self引用?这就是C ++的演变过程,Bjarne Stroustrup在其出色的着作“C ++的设计和演变”中详细讨论过。

回到operator=情况。在C ++中,您通常可以执行以下构造:x = y = z;,由于从右到左的分配关联,其排序类似于x = (y = z);

如果您的作业是void operator=(Fraction const&),则无法用于进行作业链接。不支持分配链接将是"摩擦"对于任何习惯于预期的赋值行为以及C ++内置类型如何允许链接的人来说。

为什么返回Fraction&Fraction对象,不仅仅是简单的性能优化。因为如果你做(x = y).negate();假设否定方法将在临时而非x上运行。

答案 1 :(得分:3)

  

为什么重载赋值必须返回引用而不是值?

好吧,请考虑赋值的语义。

X a(0);
X b(42);

a = b;

最后一行是否应该创建一个新的临时X对象?我想不出你为什么要这样做,但那会是operator=返回一个值的效果。

那么为什么它会返回一个参考?因为内置类型具有这些赋值语义:

ssize_t rc;
if ((rc = write(fd, buf, sz)) != sz) {
    // handle error
}

也就是说,您可以在外部表达式中使用赋值表达式的值。该值与赋值后的左侧的值相同。如何为用户定义的类型获得相同的行为?

有关激励性的例子,请考虑

std::vector<int> v;
if ((v = make_huge_vector()).empty()) {
  // it's not supposed to be empty
}

为此创建(希望)大量向量的冗余临时副本是否合理?

  

“* this”将表示为取消引用

当您取消引用指向对象的指针时,您将获得对该对象的引用。否则,再次引用指针必须创建对象的临时副本。考虑:

X *x = new X;
x->init();

相同
(*x).init();

我们应该初始化x指向的对象的副本吗?我们永远无法初始化分配的对象。因此,(*x)评估的唯一理智是对象的引用。

答案 2 :(得分:1)

它返回一个引用,因此您可以在分配对象后对该对象执行进一步操作:

struct A {
  void doSomething();
  A& operator=(const A&);
};
A a;
A b;
(a = b).doSomething();

如果赋值运算符按值返回,那么您将在未命名的临时对象上调用doSomething(),而不是a。这没用。