繁体   English   中英

具有返回值的函数(C ++)

[英]Functions with return values (C++)

当main()调用一个返回值为某种数据类型(原语或用户定义)的函数时,调用该函数的语句“通常”是一个赋值。

例如: -

class complex
{

private:

    int real;
    int imag;

public:

    complex();
    complex(int r,int i);
    complex operator + (complex c);
};

假设,我的重载“+”的定义是这样的 -

complex complex::operator + (complex c)
{
    this->real = this->real + c.real;
    this->imag = this->imag + c.imag;
    return *this;
}

我的主要功能如下 -

int main()
{
    complex c1;
    complex c2(5,4);
    c1+c2;
}

在上面的main()中,考虑语句c1 + c2 编译器将其视为c1.operator +(c2) 当main调用此函数时,它会向main()返回一个值。 这个返回值会发生什么变化?

代码忽略表达式c1+c2的值,因为您没有将其存储在任何位置。 最多,编译器将打印一些警告消息。 要压制此类警告消息,您可以写:

(void)(c1+c2); //casting to void suppresses the warning messages!

看到这个:


你的代码真正的问题..

但是,在您的代码中, operator+的实现在语义上并不正确。 要理解这一点,

 int a=10;
 int b=5;

那么,你希望a+b来改变的值a 如果a变成15 没有。

如果你想要那个,那么你会写a+=b代替。 但是在你的代码中, c1+c2行为等同于c1+=c2的语义,因为你在operator+的实现中更新this->realthis->imag的值,这在语义上是不正确的。

所以第一个修复是这样的:

complex complex::operator + (const complex& c) const
{                            
  complex result(c); //make a copy of c
  result.real += this->real; //add
  result.imag += this->imag; //add
  return result;
}

现在,这在语义上是正确的。

也就是说,仍有一些事情需要注意。 当你编写c1+c2 ,你认为操作+是否应用于任何一个对象? 不。它不适用于它们中的任何一个,但是成员函数operator+c1对象上被调用, this对象在函数内部成为this指针。 如果操作不适用于c1 (或c2 ),为什么要调用它?

该分析清楚地表明, operator+不应该是该类的成员函数。 它应该是非成员函数 ,然后签名将是:

complex operator+(const complex &a, const complex &b);

但是有一个小问题:在计算a+b ,它需要访问类(私有成员realimag是私有成员)。 所以解决方案是, operator+应该用operator+= ,后者应该作为成员函数添加到类中, 因为表达式a+=b中的操作+=确实适用于a ,因为它修改了它的值。

所以这是我对两个运算符的实现:

class complex
{
  //...
  public:

    //member function
    complex& operator+=(const complex & c)
    {
          real += c.real; //same as: this->real+=c.real; this is implicit
          imag += c.imag; //same as: this->imag+=c.real; this is implicit
          return *this;
    }
};

//non-member function (its non-friend as well)
complex operator+(const complex &a, const complex &b)
{
    complex result(a); //make copy of a by invoking the copy-constructor
    result += b;  //invokes operator+
    return result;
}

或者你可以加入最后两个声明:

complex operator+(const complex &a, const complex &b)
{
    complex result(a); //make copy of a by invoking the copy-constructor
    return result += b;  //invokes operator+, and then return updated 'result'
}

但还有另一种制作副本的方法。 为什么通过引用传递两个参数? 按值传递第一个参数将使我们需要的副本。 所以更好的实现是这样的:

complex operator+(complex a, const complex &b)
{               //^^^^^^^^^ pass-by-value
    a += b; //a is a copy, after all - we can modify it!
    return a;
}

希望有所帮助。

它被分配到一个时间(如果可能的话,不可见)复杂的值。 这种值的生命周期直到生成它的表达式结束,那就是; 在c1 + c2的末尾。 因此,创建一个新的临时对象来存储表达式的结果,并在该行的末尾对其进行破坏。

您不应该在a + b运算符中修改'this',在评估a + b之后,现在a保存表达式的结果。

return值被丢弃; 因为你没有把它存放在任何地方。

一个重要的建议

理想情况下, operator +的定义应如下所示。

complex complex::operator + (const complex& c)
{                            ^^^^^^^^^^^^^^
  complex add; 
  add.real = this->real + c.real;
  add.imag = this->imag + c.imag;
  return add;
}

在您的原始代码中,制作了2份complex ; 其中至少1可以通过上述格式避免,其中参数通过const引用

此外,在您的代码中,您不应该更改当前对象; (否则它变得像operator +=() )。 因此在函数内部创建一个临时函数并按值传递它。

在这种情况下,它会被静默删除(但总和存储在c1c2 )。 编译器可能(或可能不)通过完全删除行来优化代码,因为它没有做任何实质性的事情。 结果总和将由operator+构造和返回(将创建一个临时变量),然后立即销毁。

在其他情况下也会发生这种情况。 考虑一下:

c2 += c1;

您可以将这样的几个附加链接在一起:

c4 += c3 += c2 += c1;

这是因为operator+= 返回一个值,但是在代码中会被忽略。

顺便说一句,我认为你想使用operator+=

它被简单地丢弃,但是当期望返回值的函数没有return语句时,AFAIK C ++将显示错误。

另一种解决方案是在全局范围内使用operator + ,但作为您班级的朋友:

class complex
{
    // ...

public:

    // ...

    friend complex operator +(const complex &c1, const complex &c2)
    {
        complex c;
        c.real = c1.real + c2.real;
        c.imag = c1.imag + c2.imag;
        return c;
    }

    // ...

};

使用此技术,您还可以使用整数作为参数(在lhs)添加:

    friend complex operator +(const int n, const complex &c)
    {
        complex c;
        c.real = n + c.real;
        c.imag = c.imag;
        return c;
    }

    friend complex operator +(const complex &c, const int n)
    {
        complex c;
        c.real = c.real + n;
        c.imag = c.imag;
        return c;
    }

所以现在你也可以这样做

 complex c1, c2, c3;
 c3 = 1 + c2 + 8 + c1 + 2;

并且你的类缺少(虚拟)析构函数,我也会使成员变量受保护而不是私有:)

暂无
暂无

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

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