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



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

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

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

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

指针是一种数据类型,它保存指针指向的类型的内存地址,如果它不引用任何内容,则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上运行。

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

好吧,考虑赋值的语义。

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)来说,唯一理智的事情是评估对象。

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

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

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

最新更新