5

最近我做了一个作业,关于使用模板重载复杂类的基本功能主义者(+,-,共轭...)。我不得不费力地找出正确的返回类型(转换为更高的类型),但最后,我让它完美地工作了。这就是我的班级的样子 -

template <typename T> class complex_t
{ 
private:
    T real;
    T imaginary;

public:

complex_t(T X, T Y)
  {
    real=X;
    imaginary=Y;
  }
}

但是我没有得到满分,因为我没有实现+=,-=等运算符。为什么实施这些运算符很重要?这样做是否真的提供了任何特别的好处?任何人都可以分享一些想法吗?

提前致谢,

4

7 回答 7

9

重载运算符 - 允许您的类“Foo”的用户编写如下代码:

Foo f1 = ...;
Foo f2 = ...;
f2 = f2 - f1;

重载运算符 -= 允许用户编写

Foo f1 = ...;
Foo f2 = ...;

f2 -= f1;

除非您重载 -=,否则第二个示例将无法正常工作,而您的用户可能希望它能够工作。

编辑以合并效率点 (我的答案得到了赞成,所以我想我会从其他答案中总结一个重复出现的点,以将所有细节都集中在一个地方。感谢 larsmans 和 Benjamin)

f2 -= f1通常比f2 = f2 - f1以下两个原因更有效:

  • operator -this在修改副本并返回之前,需要获取, 的副本。
  • operator -还需要按值返回结果(它不能返回对堆栈对象的引用),可能会导致第二次复制。

operator -=另一方面,this就地修改,所以不复制。

于 2012-10-05T11:57:12.037 回答
9

如果您有两个对象 A 和 B,并且您想将 A 增加 B,而没有operator+=,您可以这样做:

A = A + B;

在正常实现中,这将涉及创建第三个(临时)对象,然后将其复制回 A。但是,使用operator+=,可以就地修改 A,因此这通常工作更少,因此效率更高。

也许更重要的是,它对语言来说是惯用的。C++ 程序员期望如果他们能做到这一点:

A = A + B;

他们也可以这样做:

A += B;
于 2012-10-05T11:58:40.397 回答
6

+=和朋友就地工作,所以你不必返回你的类的新实例。对于复数,这可能不是什么大问题,但是对于较大的结构,复制可能会很昂贵。

例如,假设您在数学意义上实现支持任意长度的向量。

class Vector
{
    std::vector<double> elements;

  public:
    Vector operator+(double x)
    {
        // must return a copy!
        Vector v(*this);
        for (size_t i=0; i < elements.size(); i++)
            v.elements[i] += x;
        return v;
    }

    Vector &operator+=(double x)
    {
        // in-place operation
        for (size_t i=0; i < elements.size(); i++)
            elements[i] += x;
        return *this;
    }
};
于 2012-10-05T11:56:32.503 回答
5

首先,如果你给我一个带有 + 运算符的类,我希望 += 也能正常工作。但是,这不会自动发生,因此您需要实现它。

其次,正如其他人之前指出的那样,根据您的类的实现和求和运算的定义,您可能能够实现 += 比仅仅以明显的方式重用您的 + 运算符更有效(即它可以由编译器自动生成的方式,但不是)。

于 2012-10-05T12:03:17.377 回答
4

因为这就是内置运算符的工作方式。任何时候你有一个二元运算符op,你都有一个变体 op=,它相当于,除了只计算一次。如果要定义重载运算符,则应在内置运算符上对其行为进行模式化(如果行为不能自然地在内置运算符上进行模式化,则不应重载)。提供,但不提供,就像提供,但不提供。a op= b;a = a op b;a++=<<=

在实践中,实现算术运算符的常用方法是仅定义op=类中的运算符,然后从类模板的实例派生,该类模板 op使用op= 运算符定义运算符,例如:

class MyType : public BinaryOperators<MyType>
{
public:
    MyType& operator+=( MyType const& other );
    //  ...
};

BinaryOperators看起来像:

template <typename ValueType>
class BinaryOperators
{
    friend ValueType
    operator+( ValueType const& lhs, ValueType const& rhs )
    {
        ValueType results( lhs );
        results += rhs;
        return results;
    }
    //  ...
};

(在这种情况下,friend声明只是允许在类中完全定义自由函数的技巧。)

于 2012-10-05T12:35:51.930 回答
3

+ 运算符将按设计分配并构造一个全新的对象,而 += 运算符可以修改现有对象。这使您可以更有效地实现 += 运算符,而不是用户用val1 = val1 + val2.

此外,当我知道一个类重载 + 时,我也希望它重载 +=。

于 2012-10-05T11:59:57.533 回答
1

除了其他程序员可能期望 += 被覆盖之外,我认为继承和覆盖功能可能是必要的。在一个非常抽象且可能不正确的意义上,假设我们想要对包含我们特殊 Integer 的 Integer 列表执行操作:

MyModifiedInteger extends Integer {
  private boolean bigNumberFlag = false;
  ...
  @Override
  public void +=(int i) {
    this = this + i;
    if (this > 100) {
      this.bigNumberFlag = true;
    }
  }
}
MyModifiedInteger myModifiedInt = new MyModifiedInteger();
List<Integer> integers = new ArrayList<Integer>();
integers.add(myModifiedInt);
for (Integer i : integers) {
  i+=5;
}

这里的想法(如果我正确应用了我的 java 继承)是在我的整数上使用 += 运算符以及可能以不同方式处理 += 操作的继承类。

于 2012-10-05T12:36:25.560 回答