代码之家  ›  专栏  ›  技术社区  ›  Salman A

规范运算符重载?

  •  7
  • Salman A  · 技术社区  · 16 年前

    在C++类类中实现算术运算符重载有一个规范的或推荐的模式吗?

    从C++ FAQ中,我们有一个异常安全的赋值操作符,避免了大多数问题:

    class NumberImpl;
    
    class Number {
       NumberImpl *Impl;
    
       ...
    };
    
    Number& Number::operator=(const Number &rhs)
    {
       NumberImpl* tmp = new NumberImpl(*rhs.Impl);
       delete Impl;
       Impl = tmp;
       return *this;
    }
    

    但对于其他运算符(+、+=等),除了让它们像内置类型上的运算符一样工作外,几乎没有给出任何建议。

    有没有一个标准的方法来定义这些?这就是我想到的——有没有我看不到的陷阱?

    // Member operator
    Number& Number::operator+= (const Number &rhs)
    {
        Impl->Value += rhs.Impl->Value; // Obviously this is more complicated
        return *this;
    }
    
    // Non-member non-friend addition operator
    Number operator+(Number lhs, const Number &rhs)
    {
         return lhs += rhs;
    }
    
    4 回复  |  直到 12 年前
        1
  •  4
  •   John Mulder    16 年前

    在比亚恩·斯特劳斯鲁普的书中” The C++ Programming Language “,在第11章(专门讨论运算符重载的章节)中,他学习了复杂数字类型的witting类(第11.3节)。

    我注意到的一件事是他实现了混合类型的操作…这可能是任何数值类的期望值。

    总的来说,你所拥有的看起来不错。

        2
  •  4
  •   ehird    12 年前

    编写任何运算符时要考虑的一个重要问题是,成员运算符不在左侧参数上进行转换:

    struct example {
      example(int);
      example operator + (example);
    };
    
    void foo() {
      example e(3), f(6);
      e + 4; // okay: right operand is implicitly converted to example
      e + f; // okay: no conversions needed.
      6 + e; // BAD: no matching call.
    }
    

    这是因为转换从不适用于 this 对于成员函数,这扩展到了运算符。如果接线员是 example operator + (example, example) 在全局命名空间中,它将编译(或者如果使用了pass-by-const-ref)。

    因此,对称运算符 + - 通常作为非成员实现,而复合赋值运算符 += -= 作为成员实现(它们也会更改数据,这意味着它们应该是成员)。而且,由于您希望避免代码重复,对称运算符可以按照复合赋值的方式实现(正如在代码示例中一样,尽管约定建议在函数内部进行临时操作)。

        3
  •  3
  •   wilhelmtell    16 年前

    惯例是写 operator+(const T&) operator-(const T&) 依据 operator+=(const T&) operator-=(const T&) . 如果在基元类型中添加和减去是有意义的,那么应该编写一个从基元类型构造对象的构造函数。然后,重载的运算符也可以用于基元类型,因为编译器将隐式调用适当的构造函数。

    正如您自己提到的,您应该避免为不需要它的函数授予访问权限。但在你上面的代码中 operator+(Number, const Number&) 我个人会把这两个参数都作为常量引用,并使用一个temp。我认为你问题下面的评论人错过了这一点并不奇怪;除非你有充分的理由不这样做,否则要避免惊喜和诡计,并尽可能地显而易见。

    如果希望代码与其他数字类型集成,请说 std::complex ,注意循环转换。也就是说,不要供应 operator OtherNumeric() 在里面 Numeric 如果 OtherNumeric 提供接受 数字的 参数。

        4
  •  3
  •   Loki Astari    16 年前

    传统上,用运算符X=X来编写运算符X
    传统上,标准运算符的所有参数都是常量。

    // Member operator
    // This was OK
    Number& Number::operator+= (Number const& rhs) 
    {
        Impl->Value += rhs.Impl->Value; // Obviously this is more complicated
        return *this;
    }
    
    // Non-member non-friend addition operator
    Number operator+(Number const& lhs,Number const& rhs)
    {
         // This I would set the lhs side to const.
         // Make a copy into result.
         // Then use += add the rhs
         Number result(lhs);
         return result += rhs;
    }
    

    你提到了分配运算符。
    但是您没有提到复制构造函数。因为您的类拥有一个原始指针的所有权,所以我希望您也定义它。然后,传统上使用复制构造函数编写赋值运算符。