简体   繁体   English

为什么 operator = 返回 *this?

[英]Why does operator = return *this?

Say I want to override the operator = so I can do something like假设我想覆盖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

Then in my implementation of the operator = , I have something like this:然后在我对operator =的实现中,我有这样的东西:

Poly& Poly::operator=(const Poly &source) {
    // Skipping implementation, it already works fine…
    return *this;
}

Don't mind the implementation, it already works fine.不要介意实施,它已经可以正常工作了。

My concern is that what happens when you return *this ?我担心的是当你return *this时会发生什么? I know it returns a reference to the object but is this what happens?我知道它返回对对象的引用,但会发生这种情况吗?

p2 = &p1

You return *this so you can write normal compound C++ = statements like: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

because that statement is basically:因为那句话基本上是:

p3.operator=(p2.operator=(p1));

If p2.operator=(...) didn't return *this you'd have nothing meaningful to pass into p3.operator=(...) .如果p2.operator=(...)没有return *this你将没有任何意义传递给p3.operator=(...)

p2 = p1 is a shorthand for p2.operator=(p1) . p2 = p1p2.operator=(p1)的简写。 It is just calling your operator= function, which is returning a reference to p2 , which you are then ignoring.它只是调用您的operator=函数,该函数返回对p2的引用,然后您将忽略它。 To make this clear, let's call it assign instead of operator= :为了清楚起见,我们称它为assign而不是operator=

Poly& Poly::assign(const Poly &source) {
    .
    .
    .
    return *this;
}

Now instead of p2 = p1 , you would write现在代替p2 = p1 ,你会写

p2.assign(p1);

In this case, the result of calling assign is being ignored, but you don't have to ignore it.在这种情况下,调用assign的结果将被忽略,但您不必忽略它。 For example, you could write:例如,你可以写:

p3.assign(p2.assign(p1));

Using operator= instead of assign , this becomes使用operator=而不是assign ,这就变成了

p3 = (p2 = p1);

but since assignment is right-associative, this can also be written as但由于赋值是右结合的,这也可以写成

p3 = p2 = p1;

This form of being able to do multiple assignments at once originally comes from C and has been preserved in C++ through the convention of returning *this in operator=() .这种能够同时进行多项赋值的形式最初来自 C,并通过在operator=()中返回*this的约定保留在 C++ 中。

One might be tempted to make the copy-assignment operator return void if you won't ever need chained assignments (as shown in the other answers) anyway.如果您无论如何都不需要链式赋值(如其他答案所示),则可能会试图让复制赋值运算符返回void After all, chained assignments are often hard to read and understand, so not allowing them might be considered an improvement .毕竟,链式赋值通常难以阅读和理解,所以不允许它们可能被视为一种改进

However, an often overlooked aspect is that void operator=(Poly& const) means that your type would no longer fulfuill the CopyAssignable concept , which requires a T& return type.但是,一个经常被忽视的方面是void operator=(Poly& const)意味着您的类型将不再满足CopyAssignable概念,这需要T&返回类型。

A type which does not fulfill the CopyAssignable concept cannot be officially used for some standard-container operations, for example std::vector::insert , which means that the following seemingly innocent piece of code yields undefined behaviour, even though it probably runs perfectly fine:不符合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
}

As the C++ standard explains in § 17.6.4.8/2.3 where it talks about constraints on programs using the standard library:正如 C++ 标准在 § 17.6.4.8/2.3 中解释的那样,它讨论了对使用标准库的程序的约束:

(...) the effects are undefined in the following cases: (...) 在以下情况下效果未定义

(...) for types used as template arguments when instantiating a template component, if the operations on the type do not implement the semantics of the applicable Requirements subclause (...). (...) 对于在实例化模板组件时用作模板参数的类型,如果对该类型的操作未实现适用要求子条款 (...) 的语义

Of course, it's precisely because of the undefined behaviour that a compiler is allowed to ignore the error and make the program behave nicely, matching the obviously intended behaviour.当然,正是由于未定义的行为,编译器才被允许忽略错误并使程序表现得很好,与明显预期的行为相匹配。 But it's not required to do so.但这不是必需的。

You should also consider that you cannot predict all future uses of your Poly type.您还应该考虑到您无法预测Poly类型的所有未来用途。 Someone might write some template function such as:有人可能会编写一些模板函数,例如:

template <class T>
void f(T const& t)
{
    T t2;
    T t3 = t2 = t;
    // ...
}

This function would then not work with your Poly class.此功能将不适用于您的Poly类。

Just don't violate this C++ convention and you won't run into troubles.只要不违反此 C++ 约定,您就不会遇到麻烦。

what happens when you return *this?当你返回 *this 时会发生什么?

In your example ( p2 = p1; ), nothing.在您的示例( p2 = p1; )中,什么都没有。 The method copies p1 into p2 and returns a reference to the 'this' object, which the calling code doesn't use.该方法将p1复制到p2并返回对调用代码不使用的“this”对象的引用。

In code such as p3 = p2 = p1;p3 = p2 = p1; , the first invocation is p2 = p1 , which copies p1 into p2 and returns a reference to p2 . ,第一个调用是p2 = p1 ,它将p1复制到p2并返回对p2的引用。 The calling code then copies from that reference-to- p2 into p3 (and ignores the reference to p3 that is returned).然后调用代码从该对p2的引用复制到p3 (并忽略返回的对p3的引用)。

(In passing: do your unit tests ensure that p1 = p1 works properly? It's easy to forget that case!) (顺带一提:您的单元测试是否确保p1 = p1正常工作?很容易忘记这种情况!)

Returning a reference to the target object allow assignment chaining (cascading), and overloading operators within a class follows right-associative (click here for detailed operator overloading rules)返回对目标对象的引用允许赋值链接(级联),并且类内的重载运算符遵循右关联(单击此处了解详细的运算符重载规则)

Poly a, b, c;
a = b = c;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM