【发布时间】:2012-01-28 20:34:11
【问题描述】:
在我的 C++ 课程中,他们正在讨论如何创建赋值运算符。在分配的最后是“return *this”行,他们说它返回了对“this”指向的对象的引用。为什么它返回一个引用?如果“this”被取消引用,它不应该只返回对象吗?
【问题讨论】:
-
我不确定...但很可能您的返回类型类似于“int&”而不是简单的“int”,您注意到了吗?
标签: c++
在我的 C++ 课程中,他们正在讨论如何创建赋值运算符。在分配的最后是“return *this”行,他们说它返回了对“this”指向的对象的引用。为什么它返回一个引用?如果“this”被取消引用,它不应该只返回对象吗?
【问题讨论】:
标签: c++
如果函数的声明(即它的签名)告诉我们,函数会返回一个引用。
所以(假设是class Foo)如果声明了一个函数
Foo fun();
然后它返回一个值(复制等)
但是如果声明为
Foo& fun();
或作为
const Foo& fun();
返回一个引用。
语句return *this; 不自行定义是否返回引用或值。
【讨论】:
它返回您所在类型 MyClass 的当前实例。它作为引用返回,因为赋值运算符被明确告知要返回一个引用。
MyClass& operator = (MyClass& other) { return *this; }
注意 MyClass 后面的 & 作为返回值。返回一个引用。
除非& 在operator 之前不存在,否则实例将按值返回。
【讨论】:
*this
在赋值的最后一行是“return *this”,他们说它返回了对“this”指向的对象的引用
他们错了。
为什么它返回一个引用?
没有。
如果“this”被取消引用,它不应该只返回对象吗?
是的!
取消引用指针会产生一个左值。这意味着*this 的结果是this 指向的实际对象。这不是参考,但也不是副本。
[C++11: 5.3.1/1]:一元*运算符执行间接:应用它的表达式应该是一个指向对象类型的指针,或者是一个指向函数类型的指针,结果是一个左值,指向表达式指向的对象或函数。 如果表达式的类型是“指向T的指针”,则结果的类型是“T”。 [..]
这可能很难概念化,因为您永远无法在代码中自己做到这一点;它只是用于本地指针的 * 运算符的一个功能,并且自 C 以来一直存在。
operator=返回
因为你不能自己做,通常你会将该 lvalue 表达式绑定到一个引用,以便在不同的上下文中使用它。例如,return *this 中的表达式 *this 绑定到您要从中返回的函数的返回类型;在这种情况下,一个赋值运算符。
现在,我们可以让赋值运算符按值返回,在这种情况下,将从来自*this 的左值复制一个对象;但是,对于赋值运算符,我们通常通过引用返回,这样我们就可以避免几乎肯定不必要的复制,并且可以执行链接:
Type a, b, c;
c = b = a;
这是一个有好处的约定,没有坏处。你能想出一个你希望op=按值返回的情况吗?
【讨论】:
每个取消引用的指针都是对其指针对象的引用,否则您将“松散”您所指向的指针对象。
在同一个对象上调用方法两次,使用指针和引用:
MyClass* objPtr = .... ;
objPtr->doSomething();
MyClass& objRef = *objPtr;
objRef.doSomething();
在不同的对象上调用方法;原件和复印件:
MyClass* objPtr = .... ;
objPtr->doSomething();
MyClass objCopy = *objPtr; //here, the reference is passed to the (implicit or implemented) copy constructor if possible, else a compile time error occurs.
objCopy.doSomething();
这意味着,如果您从具有 MyClass (rvalue) 而不是 MyClass& (lvalue) 作为返回类型的运算符方法返回引用,则 *this (MyClass&) 的副本是通过引用创建的(撇开返回值优化和右值引用)。 这对于非修改 const 方法(例如 + 和 -)很有用,它们具有新值作为结果,同时保持调用此方法的对象不被修改。
像 += 这样的操作符和你的赋值操作符按照约定在原地修改对象,因此应该返回一个引用以允许像原始类型这样的表达式支持它,因为临时副本可能会消失并导致意外结果:
考虑这个表达式:
int i = 4;
int r = (i += 3) <<= 2;
结果 r 为 28(相加并就地移位)。 我的价值是多少? 28也是,还有什么。
但是如果假设 int::operator+= 会返回自身的副本而不是对自身的引用呢?
结果 r 也是 28。
但是 i 的值呢? 它将是 7,因为就地左移被应用于从加法返回的临时 int,然后分配给 r。
继续假设,错误可能与此表达式具有相同的效果(i中的值除外):
int r = (i + 3) <<= 2;
但幸运的是,编译器会抱怨,他没有来自 (i + 3) 的左值引用来执行移位/赋值操作。
但是玩这个:
class Int
{
private:
int val;
public:
Int(int val) :
val(val)
{
}
Int operator+(const Int& other)const
{
return val + other.val;
}
Int operator+(int prim)const
{
return val + prim;
}
Int& operator+=(const Int& other)
{
val += other.val;
return *this;
}
//Error here, Int& would be correct
Int operator+=(int prim)
{
val += prim;
return *this;
}
Int operator<<(const Int& other)const
{
return val << other.val;
}
Int operator<<(int prim)const
{
return val << prim;
}
Int& operator<<=(const Int& other)
{
val <<= other.val;
return *this;
}
Int& operator<<=(int prim)
{
val <<= prim;
return *this;
}
operator int()const{
return val;
}
};
int main()
{
Int i = 4;
Int r = (i += 3) <<= 2;
cout << i;
return 0;
}
【讨论】:
在 C++ 中,* 总是表示一个值,实际上您可以查看这些运算符的英文解释如下:
&:地址
*: 的值
所以当您说&x 时,它的意思是“x 的地址”,而当您说*x 时,它的意思是“x 指向的值”。所以*this 总是会返回一个值。
只要确保返回的函数本身不是引用函数。请记住,在 C++ 中,您也可以使用 & 或 * 运算符创建函数。
【讨论】: