7

是否有规范或推荐的模式用于在 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

4 回答 4

4

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

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

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

于 2009-01-07T23:51:53.217 回答
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)。

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

于 2009-01-08T01:06:29.667 回答
3

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

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

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

于 2009-01-07T23:52:32.700 回答
3

将运算符 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 指针的所有权,我希望您也可以定义它。赋值运算符传统上是根据复制构造函数编写的。

于 2009-01-08T00:28:59.367 回答