我试图在第9章末尾的Bjarne Stroustrup的书" Programming:Principles and Practice using C++ "中进行练习.我复制大多数代码从书只需要定义Date类的成员函数add_day(),add_month(),add_year(),和超负荷+运营商为它与工作Chrono::Date::Month枚举.
我的问题是程序编译,但在我使用Chrono::Date::add_month()函数时崩溃main().add_month()是唯一一个+在Month枚举上使用重载运算符的函数.另外两个成员函数(add_day()和add_year())在使用时工作正常main().当我正在add_month()完成直接操作main()(不使用该函数)时,它工作正常.
崩溃发生在Chrono.cpp的第100行,错误为"Stack Overflow":
Date::Month& operator + (Date::Month& m, int n) {
Run Code Online (Sandbox Code Playgroud)
这是我的代码:
Chrono.h:
#include "../../std_lib_facilities.h"
namespace Chrono {
class Date {
public:
enum Month {
jan = 1, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec
};
class Invalid {}; // à utiliser comme exception
Date(int yy, Month mm, int dd); // vérifie la validité et initialise
Date(); // constructeur par défaut
//opérations non modificatrices:
int day() const {return d;}
Month month() const {return m;}
int year() const {return y;}
//opérations modificatrices:
void add_day(int n);
void add_month(int n);
void add_year(int n);
private:
int y;
Month m;
int d;
};
bool is_date(int y, Date::Month m, int d); // vrai pour une date valide
bool leapyear(int y); // vrai si l'année est bissextile
int days_in_month(Date::Month m, int y);
bool operator == (const Date& a, const Date& b);
bool operator != (const Date& a, const Date& b);
ostream& operator << (ostream& os, const Date& d);
istream& operator >> (istream& is, Date& dd);
Date::Month& operator + (Date::Month& m, int n);
}
Run Code Online (Sandbox Code Playgroud)
Chrono.cpp:
#include "Chrono.h"
namespace Chrono {
// définitions des fonctions membres:
Date::Date(int yy, Month mm, int dd)
:y(yy), m(mm), d(dd) {
if (!is_date(yy,mm,dd)) throw Invalid();
}
Date& default_date() {
static Date dd(2001, Date::jan, 1);
return dd;
}
Date::Date()
:y(default_date().year()), m(default_date().month()), d(default_date().day()) {}
void Date::add_day(int n) {
if((d + n) > days_in_month(m,y)) {
add_month(1);
d = d + n - days_in_month(m,y);
}
else
d += n;
}
void Date::add_month(int n) {
//if ((m + n) > 12) {
// m = m + (n - 12);
// y += 1;
//}
//else
m = m + n;
}
void Date::add_year(int n) {
if (m==feb && d==29 && !leapyear(y+n)) {
m = mar;
d = 1;
}
y += n;
}
bool is_date(int y, Date::Month m, int d) {
// on suppose y valide
if (d<0) return false;
if(days_in_month(m,y) < d) return false;
if(m < Date::jan || m > Date::dec) return false;
return true;
}
bool leapyear(int y) {
if (y % 4 == 0 && y % 100 > 0 || y % 400 == 0)
return true;
else
return false;
}
int days_in_month(Date::Month m, int y) {
int d_i_m = 31;
switch(m) {
case Date::feb:
d_i_m = (leapyear(y))?29:28;
break;
case Date::apr: case Date::jun: case Date::sep: case Date::nov:
d_i_m = 30;
break;
}
return d_i_m;
}
bool operator == (const Date& a, const Date& b) {
return a.year() == b.year() && a.month() == b.month() && a.day() == b.day();
}
bool operator != (const Date& a, const Date& b) {
return !(a==b);
}
ostream& operator << (ostream& os, const Date& d) {
return os << '(' << d.year() << ',' << d.month() << ',' << d.day() << ')';
}
istream& operator >> (istream& is, Date& dd) {
int y, m, d;
char ch1, ch2, ch3, ch4;
is >> ch1 >> y >> ch2 >> m >> ch3 >> d >> ch4;
if (!is) return is;
if (ch1!='(' || ch2!=',' || ch3!=',' || ch4!=')') {
is.clear(ios_base::failbit);
return is;
}
dd = Date(y,Date::Month(m),d);
return is;
}
Date::Month& operator + (Date::Month& m, int n) {
return m + n;
}
enum Day {
sunday, monday, tuesday, wednesay, thursday, friday, saturday
};
//Day day_of_week(const Date& d) {
// // ...
//}
//Day next_Sunday(const Date& d) {
// // ...
//}
//Day next_weekday(const Date& d) {
// // ...
//}
}
Run Code Online (Sandbox Code Playgroud)
main.cpp(工作):
#include "Chrono.h"
int main() {
cout << Chrono::Date::jan + 1;
}
Run Code Online (Sandbox Code Playgroud)
alternate main.cpp(编译但崩溃):
#include "Chrono.h"
int main() {
Chrono::Date date;
date.add_month(1);
}
Run Code Online (Sandbox Code Playgroud)
PS:std_lib_facilities.h定义了向量,字符串和IO.它可以在这里找到.
Date::Month& operator + (Date::Month& m, int n) {
return m + n;
}
Run Code Online (Sandbox Code Playgroud)
它可能看起来不太明显,但这是一个递归调用.它一直在呼唤自己,没有终极条件.最后,通过无限调用此函数来填充堆栈.