3

Bjarne Stroustrup の本「プログラミング: C++ を使用した原則と実践」の第 9 章の最後にある演習をしようとしています。私は本からこのコードのほとんどをコピーし、Dateクラスのメンバー関数add_day()add_month()、を定義し、列挙型で動作するように演算子をadd_year()オーバーロードするだけで済みました。+Chrono::Date::Month

私の問題は、プログラムはコンパイルされますが、 のChrono::Date::add_month()関数を使用するとクラッシュすることですmain()。列挙でオーバーロードされた演算子add_month()を使用する唯一の関数です。他の 2 つのメンバー関数 (および) は、 で使用すると正常に機能します。(関数を使用せずに)直接行うことを正確に行っている場合、正常に動作します。+Monthadd_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 を定義します。こちらから入手できます。

4

1 に答える 1

6
Date::Month& operator + (Date::Month& m, int n) {
    return m + n;
}

わかりにくいかもしれませんが、これは再帰呼び出しです。終末条件なしで、自分自身を呼び出し続けます。最終的に、この関数を無限に呼び出してスタックをいっぱいにします。

于 2012-08-26T22:10:47.817 に答える