【问题标题】:++ pre-fix operator overload is not working with <<++ 前缀运算符重载不适用于 <<
【发布时间】:2020-10-29 19:48:51
【问题描述】:

这里有一点新的 C++ 开发人员。我有一个类Rational 用于表示有理数并允许用户对它们执行算术和关系运算。我重载了所有运算符并且它们都正常工作,除非我尝试将++/-- 前缀运算符(例如--Rational)或+/- 一元运算符与&lt;&lt; 输出运算符组合在一起,如:

Rational num(7, 2); // initializes rational to 7/2 (fraction)
cout << --num; // should change val to 5/2 (decrements by one)
// error: no match for 'operator<<'(operand types are 'std::ostream' {aka 'std::basic_ostream<char>'} and 'Rational')

或:

Rational num(1, 10);
cout << -num; // should change to -1/10
// error: no match for 'operator<<'(operand types are 'std::ostream' {aka 'std::basic_ostream<char>'} and 'Rational')

我不明白为什么,因为我重载了所有这些运算符以返回 Rational 对象,并且我重载了 &lt;&lt; 运算符以接受 Rational 对象。有趣的是,当我尝试这个时:

Rational num(5, 3);
cout << num;

它按预期工作。那么有人可以告诉我这里发生了什么吗?

类的相关代码:

class Rational
{
private:
    // Instance variables declarations
    int numerator, denominator;
public:
    // Constructors declarations
    Rational(int numer_val, int denom_val = 1);
    Rational();

    // Unary operators declarations
    friend Rational operator +(const Rational &num);
    friend Rational operator -(const Rational &num);
    friend Rational operator ++(Rational &num);
    friend Rational operator --(Rational &num);
    // I/O operators
    friend ostream& operator <<(ostream &outs, Rational &num);
};

// Constructors definitions

Rational::Rational(int numer_val, int denom_val) : numerator(numer_val)
{
   set_denominator(denom_val); // irrelevant
   simplify(); // irrelevant
}
Rational::Rational() : Rational(0) { }

// Unary operators definitions
Rational operator +(const Rational &num)
{
    return Rational(+num.numerator, num.denominator);
}
Rational operator -(const Rational &num)
{
    return Rational(-num.numerator, num.denominator);
}
Rational operator ++(Rational &num)
{
    num.numerator += num.denominator;
    return num;
}
Rational operator --(Rational &num)
{
    num.numerator -= num.denominator;
    return num;
}
// I/O operators
ostream& operator <<(ostream &outs, Rational &num)
{
    outs << to_string(num.numerator) + "/" + to_string(num.denominator);
    return outs;
}

【问题讨论】:

  • ostream&amp; operator &lt;&lt;(ostream &amp;outs, Rational &amp;num) -> ostream&amp; operator &lt;&lt;(ostream &amp;outs, const Rational &amp;num)
  • 比你想象的还要糟糕:你的操作符重载改变了操作符的语义。例如,前缀递增和递减运算符应该返回对修改对象的引用,而不是对象的副本。这是通过向对象返回一个 reference 来完成的。

标签: c++ operator-overloading overloading


【解决方案1】:

operator&lt;&lt; 的第二个参数绑定到左值引用:

ostream& operator <<(ostream &outs, Rational & num)
                                          // ^

但是您的所有运算符都返回 r 值。例如,当你这样做时:

cout << -num;

您正在尝试将左值引用绑定到右值,这是不允许的。

您可以通过更改 operator&lt;&lt; 以接受 const 引用来解决此问题:

ostream& operator <<(ostream &outs, Rational const & num)
                                          // ^^^^^^^

【讨论】:

  • 我见过const Rational &amp;num首选。在类型名称之后你喜欢你的 const 有什么原因吗?
  • @scohe001 之前或之后是个人喜好的问题,它没有语义上的区别(对于像这样的简单情况)。
  • @scohe001 一致性。我总是可以把它放在后面,但在某些情况下我不能把它放在前面。例如作为成员函数上的 ref 限定符,或作为指针上的顶级 const。查找“east-const vs west-const” :) 我自己就是一个东部 const 人 :)
  • @scohe001 T const &amp; 的好处之一是您不需要螺旋规则来阅读它,只需从右侧开始向左阅读即可。
  • 是的,正如@NathanOliver 指出的那样,规则就变成了“const 适用于剩下的任何东西......”,其余的可以忽略:) 它也更容易教。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-01-05
  • 1970-01-01
  • 2013-11-30
  • 2013-07-27
  • 2014-05-16
  • 1970-01-01
相关资源
最近更新 更多