在不改变原始值的情况下重载运算符的方法?

时间:2009-07-20 23:20:05

标签: c++

我想知道你是否可以重载操作符并在不改变对象原始值的情况下使用它。

编辑代码示例:

class Rational{
public:
   Rational(double n, double d):numerator_(n), denominator_(d){};
   Rational(){}; // default constructor
   double numerator() const { return numerator_; } // accessor
   double denominator() const { return denominator_; } // accessor
private:
    double numerator_;
    double denominator_;
};

const Rational operator+(const Rational& a, const Rational& b)
{
      Rational tmp;
      tmp.denominator_ = (a.denominator() * b.denominator());
      tmp.numerator_ = (a.numerator() * b.denominator());
      tmp.numerator_ += (b.numerator() * a.denominator());
      return tmp;
}

我创建了访问器const方法,但是我仍然为每个tmp.denominator_ / numerator _收到隐私错误。

5 个答案:

答案 0 :(得分:5)

也许我错过了什么,但你为什么不拿出修改参数的代码?

const Rational Rational::operator+(Rational& num)
{
      Rational tmp;
      tmp.denominator_ = (denominator_*num.denominator_);
      //numerator_*=num.denominator_;
      //num.numerator_*=denominator_;
      tmp.numerator_ = (numerator_+num.numerator_);
      return tmp;
}

这可以通过const-correct来获得。

这意味着你的功能签名应该是这样的:

Rational Rational::operator+(const Rational& num) const

然后你会因为修改const对象而得到错误。现在,您的操作员编写方式通常被认为是错误的。

当您添加2 + 3时,2和3都不会更改:它们是常量。

修改

对不起,我错过了实际的数学部分。以下是一些事项:

作为会员功能(我上面提到的),请执行以下操作:

// Note that I use lhs and rhs to refer to the left-hand
// and right-hand sides of an operation. As a member function
// my left-hand side is implicitly `this`.
Rational Rational::operator+(const Rational& rhs) const
{
    Rational temp;

    temp.denominator_ = (denominator() * rhs.denominator());
    temp.numerator_ = (numerator() * rhs.denominator());
    temp.numerator_ += (denominator() * rhs.numerator());
    return temp;
}

作为一项全球职能,请执行以下操作:

Rational operator+(const Rational& lhs, const Rational& rhs)
{
    Rational temp;

    temp.denominator_ = (lhs.denominator() * rhs.denominator());
    temp.numerator_ = (lhs.numerator() * rhs.denominator());
    temp.numerator_ += (lhs.denominator() * rhs.numerator());

    return temp;
}

这里的问题是您将获得访问冲突:您的成员变量是该类的私有变量。你需要让编译器知道如果这个函数通过使该函数成为该类的朋友来处理你的类的私有变量是可以的:

class Rational
{
public:
    friend Rational operator+(const Rational& lhs, const Rational& rhs);
}

答案 1 :(得分:3)

不..你必须重写+- ..这并不难。然后将签名更改为

const Rational Rational::operator+(Rational& num) const
const Rational Rational::operator-(Rational& num) const

如果您正在修改对象,编译器会通知您。

答案 2 :(得分:3)

您正在寻找的是“二元”加法和减法运算符:

const Rational operator+(const Rational& A, const Rational& B)
{
    Rational result;

    ...

    return result;
}

更新(以回应新代码和评论):

您收到该错误是因为您的访问器函数未声明为常量函数,因此编译器必须假定它们可能会修改原始对象。如下更改您的访问者,您应该好好去:

double numerator() const { return numerator_; }
double denominator() const { return denominator_; }

<强>更新

要正确处理隐私问题,您应该将二进制operator+函数声明为friend类的Rational。以下是它的外观:

class Rational {
public:
    Rational(double n, double d):numerator_(n), denominator_(d) {};
    Rational() {}; // default constructor
    double numerator() const { return numerator_; } // accessor
    double denominator() const { return denominator_; } // accessor
    friend Rational operator+(const Rational& A, const Rational& B);
private:
    double numerator_;
    double denominator_;
};

const Rational operator+(const Rational& a, const Rational& b)
{
    Rational result;

    result.denominator_ = (a.denominator_ * b.denominator_);
    result.numerator_ = (a.numerator_ * b.denominator_);
    result.numerator_ += (b.numerator_ * a.denominator_);

    return result;
}

答案 3 :(得分:2)

由于你的类已经提供了分子和分母的访问器,并且它有一个公共构造函数,所以不需要使用任何friend。您可以按如下方式重载operator+

const Rational operator+(const Rational& rhs, const Rational& lhs)
{
    double newNumerator = rhs.numerator() * lhs.denominator() +
                          rhs.denominator() * lhs.numerator();
    return Rational(newNumerator, rhs.denominator() * lhs.denominator());
}

回应其他一些答案:

Item 24 Rational完全回答了有关此问题的所有问题。在这个项目中,Scott Meyers表明,在处理数字类型的情况下,您希望以直观的方式支持隐式转换,最好使用非成员非朋友函数。

假设您的Rational::Rational(double numerator = 0, double denominator = 1); 类具有以下构造函数:

operator+

在这种情况下,如果Rational oneHalf(1, 2); oneHalf + 2; // works 2 + oneHalf; // error! 是成员函数,尝试进行混合模式算法只能工作一半时间:

operator+

在第二个示例中,调用整数operator+。解决此问题的方法是使Rational Item 23成为非成员函数,如上所示。

如果您可以访问Effective C ++,还应该查看{{1}}:首选非成员非朋友函数到成员函数。

答案 4 :(得分:0)

我更愿意在operator+方面实施operator+=。然后客户可以选择是否需要临时副本。此外,operator+=作为成员函数更自然,因此它可以访问私有部分。

class Rational {
public:
    Rational(double n, double d):numerator_(n), denominator_(d) {};
    Rational() {}; // default constructor

    double numerator() const { return numerator_; } // accessor
    double denominator() const { return denominator_; } // accessor

    Rational & operator+=(const Rational& b) {
        denominator_ *= b.denominator_);
        numerator_ *= (b.denominator_);
        numerator_ += (b.numerator_ * denominator_);
        return *this;
    }

private:
    double numerator_;
    double denominator_;
};


const Rational operator+(const Rational& a, const Rational& b)
{
    Rational result(a);
    result += b;
    return result;
}

然而,实现运算符重载的最简单方法是使用boost operators库。然后你实现了最小的操作符集,并加强了其余部分和所有陷阱(包括wintermute的2 + oneHalf示例。