我是C ++的新手,我从learncpp网站开始。 在赋值运算符重载章节中有这些代码行:
Fraction& Fraction::operator= (const Fraction &fraction)
{
m_numerator = fraction.m_numerator;
m_denominator = fraction.m_denominator;
return *this;
}
首先,为什么重载赋值必须返回引用而不是值?
第二件事是因为this
是一个指针本身,所以*this
将被表示为取消引用,因此它的值应该是对象,但赋值运算符的返回值是Fraction&
。我在这里有误会吗?
答案 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
。这没用。