【问题标题】:Overriding an operator using const for both parameters in C++在 C++ 中使用 const 覆盖两个参数的运算符
【发布时间】:2009-01-04 12:34:32
【问题描述】:

我正在尝试使用两个 const 参数创建一个覆盖的运算符函数,但我不知道该怎么做。这是一个简单的例子:

class Number
{
    Number()
    {
        value = 1;
    };

    inline Number operator + (const Number& n)
    {
        Number result;

        result.value = value + n.value;
        return result;
    }

    int value;
}

我在这里要做的是将两个参数传递给加法函数,它们都是 const 并返回结果而不更改类中的任何内容:

const Number a = Number();
const Number b = Number();
Number c = a + b;

这可能吗?我该怎么做?

谢谢,

【问题讨论】:

  • 可能吗? result.value = value + n.value;
  • 你是对的(正在动态编辑)- 已更改。

标签: c++ operator-overloading overriding overloading


【解决方案1】:

inline 在类声明中被理解,因此您无需指定它。

最惯用的做法是,将operator+ 设为在类定义之外声明的非成员函数,如下所示:

Number operator+( const Number& left, const Number& right );

如果它需要访问Number 的内部,您可能需要将其设为类的friend

如果您必须将其作为成员函数,那么您需要将函数本身设为 const:

Number operator+( const Number& n ) const
{ // ...

对于像Number 这样的类,operator+ 通常以operator+= 的形式实现,因为通常您希望所有常用运算符按预期工作,而operator+= 通常更容易实现,而operator+ 往往不会与单独实施相比失去任何效率。

类内:

Number& operator+=( const Number& n );

课外:

Number operator+( const Number& left, const Number& right )
{
    return Number( left ) += right;
}

甚至:

Number operator+( Number left, const Number& right )
{
    return left += right;
}

【讨论】:

  • 你不应该在 operator+ 的实现中复制“left”并修改副本吗?
  • 我不确定这是否很重要。如果 Number 有一个私有复制构造函数或者可以抛出(在这种情况下 operator+ 可以捕获它),它可以。它还可以从派生类中切分(因此,我们将失去可能需要的任何多态性)。但我认为情况并非如此。
  • 对不起,我只是误读了代码:他当然是在按值复制“左”。出于某种原因,我将其读作 Number &left。但是我会假装我在抱怨多态性的原因,如果没关系,因为它让我看起来不那么愚蠢;-)
  • 如果你正在实现一个 operator+ 那么它意味着你想要一个新的对象。它实际上只对具有值语义的对象有意义,因此切片不应该成为真正的问题。如果这是一个问题,您可能不想使用典型 operator+ 的语义来实现某些东西。
【解决方案2】:
class Number
{
    Number()
    {
        value = 1;
    };

    inline Number operator + (const Number& n) const
    {
        Number result;

        result = value + n.value;
        return result;
    }

    int value;
}

【讨论】:

    【解决方案3】:

    怎么样:

    inline Number operator + (const Number& n) const
    

    【讨论】:

      【解决方案4】:

      虽然我觉得前面的答案已经足够好,但我认为需要澄清一下。

      运算符(通常)有两种风格

      第一个是非成员函数,第二个是成员函数,其参数是操作的“右操作数”,通常返回当前修改的对象。

      例如,假设有一个运算符 § 用于类 T。它可以写成非成员函数

      T operator § (const T & lhs, const T & rhs)
      {
         T result ;
         // do the lhs § rhs operation, and puts the result into "result"
         return result ;
      }
      

      或作为成员函数

      T & T::operator § (const T & rhs)
      {
         // do the "this § rhs" operation, and puts the result into "this"
         return *this ;
      }
      

      甚至(非常不寻常)作为另一个成员函数

      T T::operator § (const T & rhs) const
      {
         T result ;
         // do the "this § rhs" operation, and puts the result into "result"
         return result ;
      }
      

      通常,您应该更喜欢非成员函数,如果只是因为您不应该将其声明为朋友。因此,使用 non-member non-friend 函数可以增强对象的封装性。

      免责声明:还有其他风格,但我将自己限制为算术运算符,如 +*/- 等,以及“可信”运算符原型。

      分析你对运算符的使用

      +的情况下:

      1. 每个操作数都需要保持不变,因为a = b + c 不得更改b,也不得更改c
      2. 你可以积累+,就像在a = b + c + d + e中一样,所以临时的必须存在。
      T operator § (const T & lhs, const T & rhs)
      {
         T result ;
         // do the lhs § rhs operation, and puts the result into "result"
         return result ;
      }
      

      +=的情况下:

      1. 您知道左操作数 A(来自 A += B)将被修改。
      2. 您知道左操作数 A(来自 A += B)是它自己的结果。

      所以你应该使用:

      T & T::operator += (const T & rhs)
      {
         // do the "this § rhs" operation, and puts the result into "this"
         return *this ;
      }
      

      一如既往,过早的优化是万恶之源

      我在生产代码中看到过这种代码,所以,它确实发生了:

      T & operator + (const T & lhs, const T & rhs)
      {
         static T result ; // result is STATIC !!!!
         // do the lhs + rhs operation, and puts the result into "result"
         return result ;
      }
      

      作者希望节省一个临时的。使用这种代码,编写 a = b + c + d 会导致有趣(和错误)的结果。

      ^_^

      最后但并非最不重要的一点

      我确实在this page 上写了一个运算符重载原型列表。该页面仍在建设中,但它的主要用途(易于复制/粘贴工作原型)可能非常有用...

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-04-25
        • 2010-12-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多