[英]Why does operator = return *this?
假设我想覆盖operator =
所以我可以做类似的事情
Poly p1; // an object representing a polynomial
Poly p2; // another object of the same type
p2 = p1; // assigns all the contents of p1 to p2
然后在我对operator =
的实现中,我有这样的东西:
Poly& Poly::operator=(const Poly &source) {
// Skipping implementation, it already works fine…
return *this;
}
不要介意实施,它已经可以正常工作了。
我担心的是当你return *this
时会发生什么? 我知道它返回对对象的引用,但会发生这种情况吗?
p2 = &p1
您return *this
这样您就可以编写普通的复合 C++ =
语句,例如:
Poly p1; //an object representing a polynomial
Poly p2;
Poly p2;
// ...
p3 = p2 = p1; //assigns all the contents of p1 to p2 and then to p3
因为那句话基本上是:
p3.operator=(p2.operator=(p1));
如果p2.operator=(...)
没有return *this
你将没有任何意义传递给p3.operator=(...)
。
p2 = p1
是p2.operator=(p1)
的简写。 它只是调用您的operator=
函数,该函数返回对p2
的引用,然后您将忽略它。 为了清楚起见,我们称它为assign
而不是operator=
:
Poly& Poly::assign(const Poly &source) {
.
.
.
return *this;
}
现在代替p2 = p1
,你会写
p2.assign(p1);
在这种情况下,调用assign
的结果将被忽略,但您不必忽略它。 例如,你可以写:
p3.assign(p2.assign(p1));
使用operator=
而不是assign
,这就变成了
p3 = (p2 = p1);
但由于赋值是右结合的,这也可以写成
p3 = p2 = p1;
这种能够同时进行多项赋值的形式最初来自 C,并通过在operator=()
中返回*this
的约定保留在 C++ 中。
如果您无论如何都不需要链式赋值(如其他答案所示),则可能会试图让复制赋值运算符返回void
。 毕竟,链式赋值通常难以阅读和理解,所以不允许它们可能被视为一种改进。
但是,一个经常被忽视的方面是void operator=(Poly& const)
意味着您的类型将不再满足CopyAssignable
概念,这需要T&
返回类型。
不符合CopyAssignable
概念的类型不能正式用于某些标准容器操作,例如std::vector::insert
,这意味着以下看似无辜的代码片段会产生未定义的行为,即使它可能运行得很好美好的:
#include <vector>
struct Poly
{
void operator=(Poly const&) {} // Poly is not CopyAssignable
};
int main()
{
std::vector<Poly> v;
Poly p;
v.insert(v.begin(), p); // undefined behaviour
}
正如 C++ 标准在 § 17.6.4.8/2.3 中解释的那样,它讨论了对使用标准库的程序的约束:
(...) 在以下情况下效果未定义:
(...) 对于在实例化模板组件时用作模板参数的类型,如果对该类型的操作未实现适用要求子条款 (...) 的语义。
当然,正是由于未定义的行为,编译器才被允许忽略错误并使程序表现得很好,与明显预期的行为相匹配。 但这不是必需的。
您还应该考虑到您无法预测Poly
类型的所有未来用途。 有人可能会编写一些模板函数,例如:
template <class T>
void f(T const& t)
{
T t2;
T t3 = t2 = t;
// ...
}
此功能将不适用于您的Poly
类。
只要不违反此 C++ 约定,您就不会遇到麻烦。
当你返回 *this 时会发生什么?
在您的示例( p2 = p1;
)中,什么都没有。 该方法将p1
复制到p2
并返回对调用代码不使用的“this”对象的引用。
在p3 = p2 = p1;
,第一个调用是p2 = p1
,它将p1
复制到p2
并返回对p2
的引用。 然后调用代码从该对p2
的引用复制到p3
(并忽略返回的对p3
的引用)。
(顺带一提:您的单元测试是否确保p1 = p1
正常工作?很容易忘记这种情况!)
返回对目标对象的引用允许赋值链接(级联),并且类内的重载运算符遵循右关联(单击此处了解详细的运算符重载规则)
Poly a, b, c;
a = b = c;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.