重载 '-' 运算符

4

我正在编写一个程序,其中有一部分需要通过重载减号运算符来确定两个日期之间的天数差。

目前,我正盯着屏幕,完全无法思考。我的脑海中有些想法,但它们只是片刻的想法。

在main.cpp中,将有两个变量,例如beethovenDeathDatebeethovenBirthDate,它们将被减去以确定他生活了多长时间。如果我记得正确的话,这大约是22000天。

所以,没有更多的话,这是我的代码:

Date.cpp

const std::string Date::MONTH_STRINGS[] = 
{
    "", //one based indexing
    "January",
    "February",
    "March",
    "April",
    "May", 
    "June",
    "July",
    "August",
    "September",
    "October",
    "November",
    "December"
};

const int Date::DAYS_PER_MONTH[] =
{
    0, //one based indexing
    31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};      

Date::Date(int day, int month, int year) : _year(year), _month(month), _day(day)
{
    isValid();
}

Date::Date()
{
    time_t t = time(0);   // get time now
    struct tm * now = localtime( & t );
    _year = now -> tm_year + 1900;
    _month = now -> tm_mon + 1;
    _day = now -> tm_mday;
}

int Date::maxDay(int month, int year)
{
    int ret = DAYS_PER_MONTH[month];
    if(isLeapYear(year) == true && month == 2)
    {
        ++ret;
    }
    return ret;
}

void Date::addDay(bool forward)
{
    if(forward)
    {
        if(_day < maxDay(_month, _year))
        {
            ++_day;
        }
        else
        {
            _day = MIN_DAY;
            ++_month;
            if(_month > MAX_MONTH)
            {
                _month = MIN_MONTH;
                ++_year;
            }    
        }
    }
    else
    {
        if(_day <= MIN_DAY)
        {
            --_month;
            if(_month < MIN_MONTH)
            {
                _month = MAX_MONTH;
                --_year;
            } 
            _day = maxDay(_month, _year);
        }
        else
        {
            --_day;
        }
    }    
}


std::string Date::toString() const
{
    if(isValid() == false)
    {
        return std::string();
    }
    std::stringstream ss;
    ss  << MONTH_STRINGS[_month] << " " << _day << ", " <<  _year;
    return ss.str();            
}    


bool Date::isValid() const
{
    if(_month < MIN_MONTH || _month > MAX_MONTH)
    {
        std::cerr << "Invalid date " << std::endl;
        return false;
    }
    int daysThisMonth = maxDay(_month, _year);

    if(_day < MIN_DAY || _day > daysThisMonth)
    {
        std::cerr << "Invalid date " << std::endl;            
        return false;   
    }
    return true;
}

bool Date::isLeapYear(int year)
{
    if(!(year % 4))
    {
        if(!(year % 100))
        {
            if(!(year % 400))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        else
        {
            return true;
        }
    }
    else
    {
        return false;
    }
}

bool Date::isLeapYear() const
{
    return isLeapYear(_year);
}

bool Date::isLeapDay() const
{
    return isLeapDay(_day, _month, _year);
}

bool Date::isLeapDay(int day, int month, int year) 
{
    if(day == 29 &&  month == 2 && isLeapYear(year) == true)
    {
        return true;
    }
    else
    {
        return false;
    }
}


void Date::addYears(int years)
{
    if(years == 0)
    {
        return;
    }
    if(isLeapDay() && !isLeapDay(_day, _month, _year + years))
    {
        _day = Date::DAYS_PER_MONTH[_month];
    }
    _year += years;
}

void Date::addMonths(int months)    
{
    if(months == 0)
    {
        return;
    }
    int deltayears = months / MAX_MONTH;
    int deltamonths = months % MAX_MONTH;
    int newMonth = 0;
    if(months > 0)
    {
        newMonth = (_month + deltamonths) % MAX_MONTH;
        if((_month + deltamonths) > MAX_MONTH)
        {
            ++deltayears;
        }
    }
    else
    {
        if((_month + deltamonths) < MIN_MONTH)
        {
            --deltayears;
            newMonth = _month + deltamonths + MAX_MONTH;
        }
        else
        {
            newMonth = _month + deltamonths;
        }       
    }
    if(_day > maxDay(newMonth, _year + deltayears))
    {
        _day = maxDay(newMonth, _year + deltayears);
    }
    _year += deltayears;
    _month = newMonth;

}

void Date::addDays(int days)
{
    if(days == 0)
    {
        return;
    }

    if(days < 0)
    {
        for(int i = 0; i > days; --i)
        {
            addDay(false);
        }
        return;
    }

    for(int i = 0; i < days; ++i)
    {
        addDay(true);
    }
}

std::ostream& operator<<(std::ostream& os, const Date& date)
{
    os << date.toString();
    return os;
}

Date Date::operator+(int days) const
{
    Date ret = *this;
    ret.addDays(days);
    return ret;
}

Date& Date::operator+=(int days)
{
    addDays(days);
    return *this;
}
//This is where I get stumped (the parameters was just one of my failed experiments
Date& Date::operator-(int day, int month, int year)
{
}

1
你是要从日期中减去几天、几个月还是几年?我这样问是因为在你的其他重载算术运算符中,你只有一个 days 参数。 - smac89
两者目的不同。我现在正在通过一本书学习,"任务"要求重载+仅将两个东西相加,而-则明确调用以确定两个变量之间的天数差异。 - Tarupron
1
所以如果是这种情况,你想要将一个日期对象作为参数,并找到两个日期之间的天数差异;而不是像你现在做的那样传入3个参数。 - smac89
sscce.org中的第一个“s”代表“short” :) - kfsone
已解决问题:http://boost.cvs.sourceforge.net/viewvc/boost/boost/boost/date_time/date.hpp?view=markup#l139 - johnsyweb
2个回答

2

这个函数可以作为成员函数或自由函数编写。 成员函数的签名如下:

TimeDuration Date::operator-(Date const & rhs) const

免费函数应该是这样的:

TimeDuration operator-(Date const & lhs, Date const & rhs)

TimeDuration是一个完全独立的类型,表示一段时间的长度。如果你愿意,你可以把它作为表示天数的int,但是在我看来,最好为此目的使用更具表现力的类型。无论你决定返回什么类型,类型不应该是Date(当然也不是Date&)。

一个可能的实现(虽然效率不是很高),假设你已经编写了一个将日期加一天的函数,那么代码可能如下所示:

if lhs_date comes before rhs_date
    add days to (a copy of) lhs_date until lhs_date == rhs_date
    return the negative of number of days added
if rhs_date comes before lhs_date
    add days to (a copy of) rhs_date until rhs_date == lhs_date
    return the number of days added
else
    return 0

你可能需要的另一个函数(或许这才是你最初想要的,但你的措辞并没有表明)是一种可以从Date中减去一段时间的函数。在这种情况下,返回值将是另一个Date对象(但不是Date&),可能的签名如下:

Date Date::operator-(TimeDuration rhs) const // member version
Date operator-(Date const & lhs, TimeDuration const & rhs) // non-member version

1
@AndrewB 没错 -- lhs - rhs. - David Schwartz
1
@AndrewB 你可以将所有内容标准化为天数,并计算差异。 - greatwolf
1
@AndrewB:你编写了一个添加一天的函数。反转逻辑,编写一个减去一天的函数应该很简单。重复这个过程,直到达到所需的天数。虽然不是最有效率的解决方案,但我会将优化留给你处理。至于TimeDuration,它目前不存在。你需要自己定义。就像我说的,你可以使用一个int(表示天数)代替它,但我更喜欢更具表现力的类型。如果你只使用一个int,你必须记录该int的含义。而有了名为TimeDuration的类型,你就不需要这样做了。 - Benjamin Lindley
1
@AndrewB:我不知道你所说的“将其转换为天数”是什么意思。日期是时间上的一个特定点(即“何时?”)。 “天数”是时间的持续时间(即“多长时间?”)。 它们是两个不同的概念。 你不能把一个变成另一个。 但是,给定一个特定的参考日期(例如公元前1年1月1日),您可以通过与该参考日期的距离来表示日期(这将是一个持续时间)。 这是你的意思吗? - Benjamin Lindley
1
@AndrewB:我相当确定我从原始问题中理解了所有内容,如果没有回答到位,我的语言表达能力也会让我感到困惑。除非为您编写所有代码(我并不是在指责您这样做),否则我真的不知道如何让这更加清晰明了。也许会有比我更好的解释者出现。 - Benjamin Lindley
显示剩余6条评论

0
你应该这样做:
//This is where I get stumped (the parameters was just one of my failed experiments
TimeDuration& Date::operator-(Date const & d1)
{
    // ... processing ...
    // this - d1;
}

并将其称为:

Date d1 = new Date(20, 01, 2013);
TimeDuration duration = d1 - (new const Date(20, 01, 1922));
// Calculate no. of days or years using duration

逻辑如下:
  1. 将两个Date对象(第一个可以是隐式的)传递给重载函数并返回TimeDuration

  2. 要调用此运算符,您可以使用您拥有的数据创建一个Date对象,而不是分别传递每个值。

请检查确切的语法。


1
Date d1 = new Date(...) 这是什么?肯定不是 C++。 - Benjamin Lindley
@BenjaminLindley,你说得对。这就是为什么我在回答的最后提到要检查确切的语法。我提供的解决方案并不是一个完全复制粘贴的解决方案,只是为了引导提问者正确实现逻辑。如果你发现逻辑有任何问题,请告诉我。 - Vivek Jain

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