【问题标题】:C++ operators overridingC++ 运算符覆盖
【发布时间】:2016-03-30 08:53:32
【问题描述】:

你能解释一下为什么这段代码不起作用。 运算符+覆盖:

Fraction& Fraction::operator+(const Fraction& f) {
    Fraction temp;
    if (this->denominator == f.denominator){
        temp.numerator = this->numerator + f.numerator;
        temp.numerator = this->numerator;
        temp.simplifier();
    }
    else {
        temp.numerator = this->numerator * f.denominator + f.numerator * this->denominator;
        temp.denominator = this->denominator * f.denominator;
        temp.simplifier();
    }
    return temp;
}

operator= 覆盖:

void Fraction::operator=(const Fraction& f) {
    this->numerator = f.numerator;
    this->denominator = f.denominator;
}

代码后

Fraction res;
res = f + g;

res 的字段保持未初始化状态。 但是,例如,代码

Fraction res = g; 

工作正常。所以 operator= 不将 (f + g) 理解为一个对象? 谢谢。

【问题讨论】:

  • 编译器应该对此发出警告;但是使用Fraction::operator+,您将返回对局部变量的引用。
  • 您的 operator+ 返回对局部变量的引用,这是未定义的行为。 Fraction res = g; 是一个初始化,它不会导致调用 operator=
  • 仅供参考,这是本网站上最好的问题和答案堆栈之一,Operator Overloading。值得一读。

标签: c++ class oop operator-keyword overriding


【解决方案1】:

问题是您的重载返回了对对象temp 的引用,该对象在函数返回时被销毁。

在函数返回后访问该对象是未定义的。

改为按值返回:

Fraction Fraction::operator+(const Fraction& f)

Fraction res = g; 

不是赋值而是初始化,不会使用你的赋值运算符。

【讨论】:

  • 具体来说,Fraction res = g; 将使用复制构造,如果你定义了一个,或者编译器提供了一个,如果你没有。 (我怀疑提供的编译器会很好。)
【解决方案2】:

您正在返回对在堆栈上创建的临时对象的引用。在 operator+ 中,“temp”的生命周期在 operator+ 返回时结束。下次调用方法时,它的内容可能会以混乱的方式改变。

【讨论】:

    【解决方案3】:

    除了返回一个临时的引用,你遇到的另一个问题是:

        if (this->denominator == f.denominator){
            temp.numerator = this->numerator + f.numerator;
            temp.numerator = this->numerator;  // *HERE*
            temp.simplifier();
        }
    

    我很确定标有 *HERE* 的行应该是:

            temp.denominator = this->denominator;
    

    否则你会用一个未初始化的分母调用 simplifier 并且会发生不好的事情。

    我还建议使operator + 成为一个独立的二元运算符,它接受两个Fraction 参数 - 并使其使用operator +=。注意:lhs 作为副本传递,不是作为 const 引用。

    Fraction operator +(Fraction lhs, const Fraction &rhs)
    {
        lhs += rhs;
        return lhs;
    }
    

    【讨论】:

      【解决方案4】:

      如果您想返回“temp”作为参考,那么您必须将“temp”声明为:

      static Fraction temp;
      

      现在一切都会好起来的。为什么因为在声明之前附加 static 关键字使“temp”在程序终止之前可用..

      【讨论】:

      • 但是不要这样做。它使一切都变得非常不安全,并且可能非常令人困惑。例如,你能说服自己a + b + c 是安全的吗?
      • 是的,我同意你的看法...谢谢。
      • 这不仅令人困惑,而且是错误的 - a + b + c + d 不会给出与 (a + b) + (c + d) 相同的结果。