我一直在尝试编写一个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 ++中的类感到困惑,我真的不明白为什么第一个在特定情况下失败。我将不胜感激任何解释。
提前致谢。
注意: 运算符&lt;&lt;不是问题的根源,但无论如何它是:
friend ostream& operator<<(ostream& out, Fraction& f)
{
out << f.num << "/" << f.den << endl;
return out;
}
答案 0 :(得分:4)
Fraction& operator+(Fraction& rightOp)
{
Fraction result;
result.num = num * rightOp.den + den * rightOp.num;
result.den = den * rightOp.den;;
return result;
}
这个问题是它返回对局部变量的引用。当函数结束时,局部变量被销毁,因此引用引用了无效的对象。
使用new
代替您解决了问题,因为它会动态分配result
个对象。这样的对象在函数结束时不被销毁。但是,这肯定不是解决方案。 operator+
的用户完全不清楚返回的引用是指动态分配的对象,并且将来需要delete
d。永远不要给用户带来负担。
相反,您应该只更改函数,使其按值返回:
Fraction operator+(Fraction& rightOp)
{
// ...
return result;
}
现在将返回result
的副本,因此在函数末尾销毁result
无关紧要。
作为补充说明,您可能希望该函数采用const Fraction&
参数。这允许在第二个操作数是右值(通常是临时对象)时调用它。
答案 1 :(得分:2)
您的+
重载会返回Fraction
by-reference 的实例。问题是Fraction
的本地实例将在表达式a + b
的末尾超出范围,但c
仍将保留对内存中该空白点的引用。
按引用返回不是你想要的。在这种情况下,通过返回by- value :
来制作副本更合适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)
// ^^^^^