为什么“return * this”会返回引用?

时间:2012-01-28 20:34:12

标签: c++

在我的C ++类中,他们讨论了如何创建赋值运算符。在赋值的最后是“return * this”行,他们说这些行返回了对“this”指向的对象的引用。为什么它会返回参考?如果“this”被取消引用,它不应该只返回对象吗?

5 个答案:

答案 0 :(得分:5)

如果一个函数的声明(即它的签名)告诉它,那么它将返回一个引用。

所以(假设class Foo)如果声明了一个函数

 Foo fun();

然后它返回一个值(复制等等。)

但如果宣布为

 Foo& fun();

 const Foo& fun();

返回引用。

如果返回引用或值,则语句return *this;不会自行定义。

答案 1 :(得分:4)

它返回您所在类型MyClass的当前实例。它作为引用返回,因为已明确告知赋值运算符返回引用。

MyClass& operator = (MyClass& other)  { return *this; }

注意MyClass之后的&作为返回值。返回引用。 除非&之前没有operator,否则实例将按值返回。

答案 2 :(得分:3)

表达式*this

  

在作业结束时是“return * this”这一行,他们说这些行返回了对“this”指向的对象的引用

他们错了。

  

为什么会返回引用?

没有。

  

如果“this”被取消引用,它不应该只返回对象吗?

是!

取消引用指针会产生左值。这意味着*this的结果是this指向的实际对象。它不是参考,但它也不是副本。

  

[C++11: 5.3.1/1]: 一元*运算符执行间接:应用它的表达式应该是指向对象类型的指针,或指向函数类型的指针,结果是左值引用表达式指向的对象或函数。如果表达式的类型是“指向T的指针”,则结果的类型为“T。”[。 ]

可能很难概念化,因为你自己永远不能在代码中自己做;它只是本地指针的*运算符的一个特性,从C开始就是


operator=

返回

因为你不能自己做,所以通常你会将 lvalue 表达式绑定到引用,以便在不同的上下文中使用它。例如,*this中的表达式return *this绑定到您要返回的函数的返回类型;在这种情况下,是一个赋值运算符。

现在,我们可以让赋值运算符按值返回,在这种情况下,对象副本将来自*this的左值;但是,对于赋值运算符,我们通常通过引用返回,以便我们避免几乎肯定不必要的副本,并且可以执行链接

Type a, b, c;
c = b = a;

这是一项有益的惯例,没有任何缺点。你能想到op=按值返回的情况吗?

答案 3 :(得分:1)

每个解除引用的指针都是对其指针的引用,否则你“松散”你指向的指针。

使用指针和引用在同一对象上调用两次方法:

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& (左值)作为返回类型,* this(MyClass&)的副本是通过引用创建的(不考虑返回值优化和右值引用)。 这对于非修改const方法(如+和 - )非常有用,它们将结果赋予新值,同时保留未修改此方法的对象。

运算符如+ =和你的赋值运算符按惯例修改对象,因此应该返回一个引用,允许像基本类型这样的表达式支持它,因为临时副本可能会消失并导致意外的结果:

考虑这个表达式:

int i = 4;
int r = (i += 3) <<= 2;

结果r为28(添加并移位到位)。 我有什么价值? 28,还有什么。

但是如果假设int :: operator + =会返回自己的副本而不是对它自己的引用呢?

结果r也是28。

但是我的价值? 它将是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;
}

答案 4 :(得分:0)

在C ++中,*总是表示一个值,实际上您可以按如下方式查看这些运算符的英语解释:

&

的地址

*

的值

因此,当您说&x时,它表示“x的地址”,当您说*x时,它表示“x指向的值”。因此*this将始终返回一个值。

请确保返回的主机不是引用函数的函数本身。请记住,在C ++中,您可以使用&amp;或*运营商。