为什么我们在赋值运算符中使用 return *this 而通常(而不是 this)当我们想要 return 对象的引用时?
Why do we return *this in asignment operator and generally (and not &this) when we want to return a reference to the object?
我正在学习 C++ 和指针,在看到这个之前我以为我理解了指针。
一方面,星号 (*) 运算符正在取消引用,这意味着它 returns 值指向的地址中的值,而与号 (&) 运算符则相反,并且returns 值存储在内存中的地址。
现在阅读有关赋值重载的内容,它说“我们 return *this
因为我们想要 return 对象的引用”。虽然从我读到的 *this
实际上 return 这个值,实际上 &this
逻辑上应该是 return 如果我们想 return 引用对象。
这怎么加起来?我想我在这里遗漏了一些东西,因为我没有在其他地方找到这个问题,但解释似乎与应该的完全相反,关于 * 取消引用的逻辑,并获得参考。
例如这里:
struct A {
A& operator=(const A&) {
cout << "A::operator=(const A&)" << endl;
return *this;
}
};
this
是一个指针,保存当前对象的地址。所以像 *this
这样取消引用指针你会得到当前对象本身的左值。而呈现的class的复制赋值运算符的return类型是A&
。所以 returning 表达式 *this
你是 returning 对当前对象的引用。
根据C++ 17标准(8.1.2本)
1 The keyword this names a pointer to the object for which a
non-static member function (12.2.2.1) is invoked or a non-static data
member’s initializer (12.2) is evaluated.
将以下代码片段视为一个简化示例。
int x = 10;
int *this_x = &x;
现在 return 对象的引用需要使用表达式 *this_x
例如
std::cout << *this_x << '\n';
&
根据上下文有多种含义。在 C 中单独使用时,I 可以是按位与运算符,也可以是符号引用的地址。
在 C++ 中,在类型名称之后,还意味着紧随其后的是对该类型对象的 引用。
这意味着你输入的是:
int a = 0;
int & b = a;
… b
将成为 事实上 a
.
的别名
在您的示例中,operator=
被设为 return 类型 A 的对象(不是指向它的指针)。这将被 uppers 函数以这种方式看到,但实际上 returned 是一个现有对象,更具体地说是调用了该成员函数的 class 的实例。
是的,*this
是(的值?)当前对象。但是指向当前对象的指针是this
,而不是&this
.
&this
,如果是合法的,将是pointer-to-pointer到当前对象。但它是非法的,因为 this
(指针本身)是一个临时对象,你不能使用 &
.
获取地址
问我们为什么不这样做会更有意义return this;
。
答案是:形成指针需要&
,但形成引用则不需要。比较:
int x = 42;
int *ptr = &x;
int &ref = x;
所以,类似地:
int *f1() return {return &x;}
int &f1() return {return x;}
您可以使用的一个简单助记符是 *
和 &
运算符匹配您要从 从 转换的对象的类型语法,而不是你要转换成的东西:
*
将 foo*
转换为 foo&
&
将 foo&
转换为 foo*
在表达式中,foo
和 foo&
之间没有有意义的区别,所以我可以说 *
将 foo*
转换为 foo
,但是上面的版本更容易记住。
C++ 从 C 继承了它的类型语法,C 类型语法以使用它们的表达式语法命名类型,而不是创建它们的语法。数组写成 foo x[...]
是因为您通过访问元素来使用它们,而指针写成 foo *x
是因为您通过取消引用它们来使用它们。指向数组的指针写成 foo (*x)[...]
是因为您通过取消引用它们然后访问元素来使用它们,而指针数组写成 foo *x[...]
因为您通过访问元素然后取消引用它来使用它们。人们不喜欢语法,但它是一致的。
引用是后来添加的,破坏了一致性,因为使用引用的语法与“直接”使用引用对象没有任何区别。因此,您不应该试图理解引用的类型语法。就是这样。
this
是指针的原因也纯粹是历史原因:this
是在引用出现之前添加到 C++ 中的。但是因为它是一个指针,你需要一个引用,你必须使用 *
来摆脱 *
.
我正在学习 C++ 和指针,在看到这个之前我以为我理解了指针。
一方面,星号 (*) 运算符正在取消引用,这意味着它 returns 值指向的地址中的值,而与号 (&) 运算符则相反,并且returns 值存储在内存中的地址。
现在阅读有关赋值重载的内容,它说“我们 return *this
因为我们想要 return 对象的引用”。虽然从我读到的 *this
实际上 return 这个值,实际上 &this
逻辑上应该是 return 如果我们想 return 引用对象。
这怎么加起来?我想我在这里遗漏了一些东西,因为我没有在其他地方找到这个问题,但解释似乎与应该的完全相反,关于 * 取消引用的逻辑,并获得参考。
例如这里:
struct A {
A& operator=(const A&) {
cout << "A::operator=(const A&)" << endl;
return *this;
}
};
this
是一个指针,保存当前对象的地址。所以像 *this
这样取消引用指针你会得到当前对象本身的左值。而呈现的class的复制赋值运算符的return类型是A&
。所以 returning 表达式 *this
你是 returning 对当前对象的引用。
根据C++ 17标准(8.1.2本)
1 The keyword this names a pointer to the object for which a non-static member function (12.2.2.1) is invoked or a non-static data member’s initializer (12.2) is evaluated.
将以下代码片段视为一个简化示例。
int x = 10;
int *this_x = &x;
现在 return 对象的引用需要使用表达式 *this_x
例如
std::cout << *this_x << '\n';
&
根据上下文有多种含义。在 C 中单独使用时,I 可以是按位与运算符,也可以是符号引用的地址。
在 C++ 中,在类型名称之后,还意味着紧随其后的是对该类型对象的 引用。
这意味着你输入的是:
int a = 0;
int & b = a;
… b
将成为 事实上 a
.
在您的示例中,operator=
被设为 return 类型 A 的对象(不是指向它的指针)。这将被 uppers 函数以这种方式看到,但实际上 returned 是一个现有对象,更具体地说是调用了该成员函数的 class 的实例。
是的,*this
是(的值?)当前对象。但是指向当前对象的指针是this
,而不是&this
.
&this
,如果是合法的,将是pointer-to-pointer到当前对象。但它是非法的,因为 this
(指针本身)是一个临时对象,你不能使用 &
.
问我们为什么不这样做会更有意义return this;
。
答案是:形成指针需要&
,但形成引用则不需要。比较:
int x = 42;
int *ptr = &x;
int &ref = x;
所以,类似地:
int *f1() return {return &x;}
int &f1() return {return x;}
您可以使用的一个简单助记符是 *
和 &
运算符匹配您要从 从 转换的对象的类型语法,而不是你要转换成的东西:
*
将foo*
转换为foo&
&
将foo&
转换为foo*
在表达式中,foo
和 foo&
之间没有有意义的区别,所以我可以说 *
将 foo*
转换为 foo
,但是上面的版本更容易记住。
C++ 从 C 继承了它的类型语法,C 类型语法以使用它们的表达式语法命名类型,而不是创建它们的语法。数组写成 foo x[...]
是因为您通过访问元素来使用它们,而指针写成 foo *x
是因为您通过取消引用它们来使用它们。指向数组的指针写成 foo (*x)[...]
是因为您通过取消引用它们然后访问元素来使用它们,而指针数组写成 foo *x[...]
因为您通过访问元素然后取消引用它来使用它们。人们不喜欢语法,但它是一致的。
引用是后来添加的,破坏了一致性,因为使用引用的语法与“直接”使用引用对象没有任何区别。因此,您不应该试图理解引用的类型语法。就是这样。
this
是指针的原因也纯粹是历史原因:this
是在引用出现之前添加到 C++ 中的。但是因为它是一个指针,你需要一个引用,你必须使用 *
来摆脱 *
.