Bjarne Stroustrup の本「プログラミング: C++ を使用した原則と実践」の第 9 章の最後にある演習をしようとしています。私は本からこのコードのほとんどをコピーし、Date
クラスのメンバー関数add_day()
、add_month()
、を定義し、列挙型で動作するように演算子をadd_year()
オーバーロードするだけで済みました。+
Chrono::Date::Month
私の問題は、プログラムはコンパイルされますが、 のChrono::Date::add_month()
関数を使用するとクラッシュすることですmain()
。列挙でオーバーロードされた演算子add_month()
を使用する唯一の関数です。他の 2 つのメンバー関数 (および) は、 で使用すると正常に機能します。(関数を使用せずに)直接行うことを正確に行っている場合、正常に動作します。+
Month
add_day()
add_year()
main()
add_month()
main()
Chrono.cpp の 100 行目でクラッシュが発生し、エラー「スタック オーバーフロー」が発生します。
Date::Month& operator + (Date::Month& m, int n) {
これが私のコードです:
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);
}
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) {
// // ...
//}
}
main.cpp (作業中):
#include "Chrono.h"
int main() {
cout << Chrono::Date::jan + 1;
}
別の main.cpp (コンパイルするがクラッシュする):
#include "Chrono.h"
int main() {
Chrono::Date date;
date.add_month(1);
}
PS: std_lib_facilities.h は、ベクトル、文字列、および IO を定義します。こちらから入手できます。