我是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
上调用。那将没有用。