0

我一直在尝试编写一个 Fraction 类并重载它的一些运算符(+、-、-、/...)。起初,我尝试这样做:

Fraction& operator+(Fraction& rightOp)
{
    Fraction result;
    result.num = num * rightOp.den + den * rightOp.num;
    result.den = den * rightOp.den;;
    return result;
}

这产生了一个尴尬的结果。在测试时,如果我使用:

Fraction a(2,3);
Fraction b(4,5);
Fraction c = a + b;
cout << c << endl;

它会正确打印。但是,如果我使用:

Fraction a(2,3);
Fraction b(4,5);
Fraction c;
c = a + b;
cout << c << endl;

它将打印 -858993460/-858993460。

然后,当我尝试将重载函数更改为:

Fraction& operator+(Fraction& rightOp)
{
    Fraction* result = new Fraction;
    result->num = num * rightOp.den + den * rightOp.num;
    result->den = den * rightOp.den;
    return *result;
}

这一切都会很好。这让我对指向 C++ 中的类感到困惑,我真的不明白为什么第一个在特定情况下会失败。我将不胜感激任何解释。

提前致谢。

注意:运算符 << 不是问题的根源,但无论如何:

friend ostream& operator<<(ostream& out, Fraction& f)
{
    out << f.num << "/" << f.den << endl;
    return out;
}
4

2 回答 2

4
Fraction& operator+(Fraction& rightOp)
{
    Fraction result;
    result.num = num * rightOp.den + den * rightOp.num;
    result.den = den * rightOp.den;;
    return result;
}

问题在于它返回了对局部变量的引用。局部变量在函数结束时被销毁,所以引用指向了一个无效的对象。

使用newinstead 为您解决了问题,因为它使result对象动态分配。这样的对象在函数结束时不会被销毁。但是,这肯定不是这里的解决方案。用户完全不清楚operator+返回的引用是指动态分配的对象,并且delete将来需要被 d。永远不要把这个负担放在你的用户身上。

相反,您应该只更改函数,使其按值返回:

Fraction operator+(Fraction& rightOp)
{
  // ...
  return result;
}

这现在将返回 的副本,因此在函数末尾result是否被销毁并不重要。result

作为附加说明,您可能希望该函数接受一个const Fraction&参数。这允许在第二个操作数是右值(通常是临时对象)时调用它。

于 2013-05-13T00:00:37.203 回答
2

您的重载返回一个by-reference+的实例。问题是本地实例将在表达式末尾超出范围,但仍会保留对内存中该空白点的引用。Fraction Fractiona + bc

按引用返回不是您想要的。在这种情况下,通过返回来制作副本更合适:

Fraction operator +(Fraction& rightOp)
{
    Fraction result;
    result.num = num * rightOp.den + den * rightOp.num;
    result.den = den * rightOp.den;;
    return result;
}

此外,建议您的>>重载Fraction通过引用获取一个实例const,因为它不会在主体内部修改它:

friend ostream& operator<<(ostream& out, Fraction const& f)
//                                                ^^^^^
于 2013-05-13T00:02:29.270 回答