重载 += 运算符

3

我有以下代码来分别重载Date类的+和+=运算符。+运算符已成功重载,它将接受一个整数n,并将Date对象增加n天。这是通过连续应用next_day函数n次来完成的。

inline Date operator+(Date d, int n)
{
    for(char j=1; j<=n; j++){
        d=d.next_day(d);
    }
    return d;
}
inline Date operator+=(Date d, int n)
{
    Date p=d+n;
    return p;
}

我已经重载了+运算符,并使用它来定义+=的重载。但尽管编译时没有出现任何错误,当我使用重载后的+=时似乎并没有产生任何效果。

以下是我的main.cpp:

#include <iostream>
#include "Date.h"
using namespace std;

int main() {

Date Initialday = Date (12,1,2012);

Initialday+=1;
cout <<"Next day = "<< Initialday <<endl;

return 0;
}

运行主函数仍然给我返回了12/1/2012而不是12/2/2012。我做错了什么?注意:我已经重载了<<,以便以可读格式输出日期对象,所以我认为这不是问题所在。
2个回答

5
简单的解决方法是按引用传递您的日期对象,修改它,并通过引用返回它。这是operator +=的预期行为。
inline Date& operator+=(Date &d, int n)
{
    d = d + n;
    return d;
}

然而,以 operator+ 来实现 operator+= 是反向的。相反地,应该采用另一种方式。operator+= 应该作用于对象的成员,直接修改它们。然后再通过这种方式来实现 operator+

inline Date& operator+=(Date& lhs, int rhs)
{
    ... // code here to modify lhs directly

    return lhs;
}

inline Date operator+(Date lhs, int rhs)
{
    return lhs += rhs;
}

非常感谢!我同意,这有点反向 - 但在这种情况下,因为我已经定义了函数next_day并且想要使用它,所以+=和+似乎同样直观。而且作为一个初学者,我认为先定义+更直观! - Patrick Jane
仅供学习,我可以问一下为什么以下代码不起作用吗?inline Date& operator+=(Date &d, int n) { Date p = d + n; return p; }它给我一个错误消息,说本地变量p被自动返回了。这是什么意思? - Patrick Jane
@PatrickJane:问题并不是一个比另一个更简单或更复杂。问题主要在于性能。operator+需要两个对象并从它们创建一个完全独立的对象。但是,没有理由让operator+=需要构造一个新对象。通过使用operator+实现operator+=,您正在复制对象,修改副本,然后将副本复制回原始对象。这是两个不必要的副本,当它只需要修改原始对象时。 - Benjamin Lindley
@PatrickJane:该实现的问题在于,首先,您正在返回对局部对象(p)的引用。当函数结束时,p将被销毁,因此返回的引用无效。其次,“operator+=”应修改其左操作数(d),但您没有这样做。相反,您正在创建一个新对象(p),用“d + n”的值进行初始化,并返回它。 - Benjamin Lindley
当我写下以下代码时:Date a { }; Date b { a + 1 };我并不希望aa + 1修改。但在上面的版本中,它确实被修改了,对吗? 因此,也许在operator+中,首先使用复制构造函数,即return Date{lhs} += rhs; - RL-S
@RL-S:不是这样的。lhs 是按值传递的,这意味着它已经是一个副本了。传入的 Date 对象不受影响。 - Benjamin Lindley

2
主要问题在于你的+=创建了一个新的日期对象并返回它。这是错误的语义,而且你没有将返回值赋给任何东西。+=操作符应该作用于它所应用的实例,并通过引用返回它:
inline Date& operator+=(Date& d, int n) {
   return d = d + n;
}

通常情况下,这将被实现为成员函数,其中+是通过+=来实现的:
class Date
{
 public:
    Date& operator+=(int n) {
       // perform whatever operation is required using
       // the state of the instance.
       return *this;
    }
};

inline Date operator+(Date lhs, int rhs) {
  return lhs += rhs; // calls member +=
}

最干净的方式是提供一个时间持续类,并通过 DateTimeDuration 实现所有运算符:

struct TimeDuration { .... };

class Date
{
 public:
  Date& operator+= (const TimeDuration& rhs) { .... }
};
inline Date operator+(Date lhs, const TimeDuration& rhs) { return lhs += rhs; }

将两个日期相加到底意味着什么? - Benjamin Lindley
@BenjaminLindley 这意味着我还没有喝咖啡。需要的是一个时间差类型,但我想我会删除这个无用的答案。 - juanchopanza
谢谢!我会将其定义在类内而不是内联,但我的任务似乎要求内联代码。 - Patrick Jane
@PatrickJane 从技术上讲,如果你在类内声明并定义一个方法,它会被隐式地视为inline。关于我和Benjamin的讨论,我们的想法是定义一个简单的“时间段”类型,可以用来添加到日期中,同时也能表达两个日期之间的差异。 - juanchopanza

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接