最近,我完成了一项任务,即使用模板重载复杂类的基本功能主义者(+, - ,共轭...)。我不得不出汗一点,找出适当的返回类型,(铸造到更高的类型),但最后,我得到它完美的工作。 这就是我班级的样子 -
template <typename T> class complex_t
{
private:
T real;
T imaginary;
public:
complex_t(T X, T Y)
{
real=X;
imaginary=Y;
}
}
但我没有得到满分,因为我没有实现+ =, - =等运算符。 为什么实施这些运营商很重要?这样做真的能带来什么特别的好处吗? 任何人都可以分享一些想法吗?
提前致谢,
答案 0 :(得分: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
,因此不会复制。
答案 1 :(得分:9)
如果您有两个对象A和B,并且想要在没有operator+=
的情况下将A增加A,则可以执行以下操作:
A = A + B;
在正常的实现中,这将涉及创建第三个(临时)对象,然后将其复制回A.但是,使用operator+=
,A可以在适当的位置进行修改,因此通常较少工作,因此更有效率。
也许更重要的是,这是语言的惯用语。 C ++程序员希望如果他们能做到这一点:
A = A + B;
他们也可以这样做:
A += B;
答案 2 :(得分: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;
}
};
答案 3 :(得分:5)
首先,如果你给我一个带+运算符的类,我希望+ =也可以运行。 但是,这不是自动生成的,因此您需要实现它。
其次,正如其他人之前指出的那样,根据你的类的实现和总和操作的定义,你可能能够实现+ =更高效,而不仅仅是以明显的方式重新使用你的+运算符(这是编译器可以自动生成的方式,但不是。)
答案 4 :(得分: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 );
// ...
};
的{{1}}运营商
运营商,如:
BinaryOperators
其中template <typename ValueType>
class BinaryOperators
{
friend ValueType
operator+( ValueType const& lhs, ValueType const& rhs )
{
ValueType results( lhs );
results += rhs;
return results;
}
// ...
};
类似于:
friend
(在这种情况下,{{1}}声明只是一个允许的技巧 自由函数在类中完全定义。)
答案 5 :(得分:3)
+运算符将通过设计分配和构造一个全新的对象,而+ =运算符可以修改现有的对象。这使得您可以比用户用val1 = val1 + val2
替换它时更有效地实现+ =运算符。
另外,当我知道一个类重载+时,我也希望它超载+ =。
答案 6 :(得分:1)
除了其他程序员希望覆盖+ =的可能性之外,我认为它可能是继承和覆盖功能所必需的。在一个非常抽象且可能不正确的意义上,想象一下我们想要在包含我们特殊整数的整数列表上执行操作:
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继承)是在我的整数上使用+ =运算符以及可能以不同方式处理+ =运算的继承类。