Canonical运算符重载?

时间:2009-01-07 23:21:22

标签: c++ operator-overloading

是否存在规范或推荐的模式,用于在类似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 个答案:

答案 0 :(得分:4)

在Bjarne Stroustrup的书“The C++ Programming Language”中,在第11章(专门讨论运算符重载的那本书)中,他经历了一个复数类型的类(第11.3节)。

我从该部分注意到的一件事是他实现了混合类型操作......这可能是任何数字类所期望的。

一般来说,你所拥有的东西看起来不错。

答案 1 :(得分:4)

编写任何运算符时要考虑的重要事项是成员运算符不会对左参数进行转换:

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)。

因此,+-等对称运算符通常实现为非成员,而+=-=等复合赋值运算符实现为成员(他们也改变数据,这意味着他们应该是成员)。并且,由于您希望避免代码重复,因此可以根据复合赋值来实现对称运算符(如在代码示例中,尽管约定建议在函数内部使用临时代码)。

答案 2 :(得分:3)

惯例是用operator+(const T&)operator-(const T&)来写operator+=(const T&)operator-=(const T&)。如果对原始类型添​​加和减去是有意义的,那么你应该编写一个构造函数来构造基本类型的对象。然后重载的运算符也适用于基本类型,因为编译器将隐式调用相应的构造函数。

正如您自己提到的,您应该避免为不需要它的函数提供访问权限。但是在上面的operator+(Number, const Number&)代码中,我个人将两个参数都引用为const并使用temp。我认为你的问题下面的评论者错过了这一点并不奇怪;除非你有充分的理由不去,避免意外和诡计,并尽可能明显。

如果您希望代码与其他数字类型集成,请说std::complex,请注意循环转换。也就是说,如果operator OtherNumeric()提供带有Numeric参数的构造函数,请不要在OtherNumeric中提供Numeric

答案 3 :(得分:3)

传统的做法是根据operator = X
来编写运算符X. 传统上标准运算符的所有参数都是const

// 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;
}

你提到了赋值算子 但是你没有提到复制构造函数。由于您的类拥有RAW指针的所有权,我希望您也可以定义它。传统上,Assignment运算符是根据复制构造函数编写的。