Modify a class method so as to accept and return only accepted date values

Hello there and Happy New year. I am trying to modify a class method so as to accept and return only accepted date range of values. I tried and wrote a code (//function in question) but as it seems it doesn't work in a sense that when I test the code by setting a date out of range it returns this date and not false. Any ideas?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include <iostream>
#include <string>

using namespace std;

class date {

    double day{};
    double month{};
    double year{};

public:
    date() {};

    date(double i, double m, double e) : date(i), month(m), year(e) {};

    void set_date(double i, double m, double e) {         //function in question
        bool check;                                        
        if (i >= 20 && i <= 15 && m != 12 && e != 2020) {
                check = false;
                cout << "False date" << endl;
        }
        else { day = i; month = m; year = e; }
    }; 
    
    double get_day() { return date; };
    
    double get_month() { return month; };
    
    double get_year() { return year; };
    
    void display() {
        cout << day << '/' << month << '/' << year << endl;
    };
};

class project {

    string title{};
    double grade{};
    string names[5];
    int studentnumber{};

public:
    project() {};
   
    project(string t, double g, int n) : title(t), grade(g), studentnumber(n) {};
    
    date hand_over_date;
    
    void set_title(string t) { title = t; };
    
    string get_title() { return title; };
    
    void set_grade(double g) { grade = g; };
    
    double get_grade() { return grade; };
    
    void set_sn(int n) { studentnumber = n; };
    
    int get_sn() { return studentnumber; };
    
    void set_names(string nm) {
        if (studentnumber < 5) {
            names[studentnumber] = nm;
            studentnumber++;
            cout << "Name is set! there are still " << 5 - studentnumber << "vacancies" << endl;

        }
        else cout << "Name isn't set ";
    };
    
    string get_names() {
        return names[studentnumber];
    };
    
    void show() {
        int i;
        cout << "\nThe title is: " << title << endl;
        cout << "hand over date:" << endl;
        paradosi.display();
        cout << "Grade is :" << grade << endl;
        cout << "foitites: " << studentnumber << endl;
        for (i = 0; i < studentnumber; i++) {
            cout << names[i];
        }
    };

};


int main()
{
    project e1;
    e1.set_title("Nanofluids");
    e1.set_grade(10);
    for (int i = 0; i < 5; i++) {
        string name;
        cout << "Give a name: ";
        cin >> name;
        e1.set_names(name);
    }
    e1.hand_over_date.set_date(22, 9, 2020);
    e1.show();

    return 0;
}
logic error :)
if (i >= 20 && i <= 15 && m != 12 && e != 2020)

for what value of i, in the real number world, is i greater than 20 AND ALSO less than 15?

also the use of doubles could cause you a strange bug here and there. Once in a while an integer will end up not fitting properly into a double, eg (bad example) it could make the year 2021 into 2020.9999999999999999999999998 or something internally and then when you treat it like an integer or with an equality statement, you get 2020 instead of 2021 and can't easily find the bug. Use integers for discrete values, use doubles when you actually need floating point. You are unlikely to see this with the small numbers you have here, but its better to not use doubles here regardless. (This issue happens for large values around 2^53 and bigger, so what you have is safe)
Last edited on
Jonnin Thank you! You are very right! Didn't notice that! Everything is ok now! Thank you for your other piece of advice as well! I will keep it in mind!
Hello geovoul,

I have been working on the "Date" class and have some changes that you may find useful:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <iostream>
#include <string>

using namespace std;

constexpr int VALID_MONTH{ 12 };

//constexpr int daysOfMonth[]{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };  // <--- Optional.
//const std::string monthNames[]{ "", "Jan", "Feb" };  // <--- Fill in the rest.     // <--- Optional.

class Date
{
    int m_day{};
    int m_month{};
    int m_year{};

    public:
        Date() {}

        Date(int day, int month, int year) : m_day(day), m_month(month), m_year(year) {}

        void set_date(int day, int month, int year)
        {         //function in question
            //bool check;  // <--- Defined, but never used outside of your original if statement.

            if (month != VALID_MONTH /*month < 1 || month > 12*/)
            {
                std::cerr << "\n     Invalid month!\n";

                month = 0;
            }

            if (day > 19 || day < 16 /*(day < 1 || day > daysOfMonth[month])*/)
            {
                std::cerr << "\n     Invalid day!\n";

                day = 0;
            }

            if (year != 2020)
            {
                std::cerr << "\n     Invalid year!\n";

                year = 0;
            }

            m_day = day; m_month = month; m_year = year;

            //if (day >= 20 && day <= 15 && month != 12 && year != 2020)
            //{
            //    check = false;
            //    cout << "False Date" << '\n';
            //}
            //else 
            //{
            //    m_day = day; m_month = month; m_year = year;
            //}
        }

        int get_day() { return m_day; }  // <--- You need a class object or did you mean m_day?

        int get_month() { return m_month; }

        int get_year() { return m_year; }

        void display()
        {
            cout << m_day << '/' << m_month << '/' << m_year << '\n';
        }
};

Starting at line 6 some constant variables would make the program much easier to use. You can add variables like "MIN_DATE", "MAX_DATE" and something for the year.

Lines 8 and 9 are options that you may or may not want to use, but an idea of how they can be used.

When it comes to naming a class or a struct starting the name with a capital letter can be very helpful. As an example Date date. The capital and lower case "D" makes each different so as not to be a conflict with the compiler.

As jonnin mentioned your variables should be "int"s. I can see no reason for needing the decimal part of the "double" unless you have a different idea that needs a better explanation.

In your original code you did this:
1
2
3
date() {};

date(double i, double m, double e) : date(i), month(m), year(e) {};

The (;) after the {}s is not necessary and is most likely ignored by the compiler. If the function has an empty block the empty {}s is all that is needed. If they define a block with code in between the (;) is not needed to end the block the closing } does this.

I reworked the "set_date" function. First understand how the individual if statements work before you try to combine everything into 1 if statement. In addition to what jonnin said about the logic of your a single if statement, as you have, does not tell you what is wrong with the date just that it is wrong. if you do not know what is wrong how can you fix the date.

The if statements here are just a start that you can work with. They can be changed to anything that better deals with what you need.

Next is line 60. Did you copy this from somewhere else and forge to change it? Or did you have something else in mind?

In the "Project" class the "show" function inside the for loop you have: cout << names[i];. This prints each name to the screen in 1 big name with no way to tell what is what.

My apologies as I do not remember to whom I said this to, but it does seem familiar. Writing the line as
cout << names[i] << ' '; will put a space between the names for a better looking output. Or you could change the space to (\n) and print each name on a separate line. Your choice.

In "main " I made 1 other change for testing. Use this for loop and you will not have to enter 5 names each time you run the program:
1
2
3
4
5
6
std::string names[]{ "Imperius", "Arya", "Navarre", "Isabeau", "Saphira" };

for (int i = 0; i < MAXNAMES; i++)
{
    e1.set_names(names[i]);
}

When you are finished testing you can remove these lines and uncomment your original code for normal use. This saves some time to concentrate on other parts of the program.

When I ran the program I got this output:

Name is set! there are still 4 vacancies
Name is set! there are still 3 vacancies
Name is set! there are still 2 vacancies
Name is set! there are still 1 vacancies
Name is set! there are still 0 vacancies

     Invalid month!

     Invalid day!

The title is: Nanofluids
hand over Date: 0/0/2020
Grade is: 10
foitites: 5
Imperius Arya Navarre Isabeau Saphira



Lastly you have several magic numbers in your code, namely 5, and this would be a good place to use a constant variable. This way if it ever changes you will only have 1 place to make this change and it will be used through out the program.

I have not made any big changes to the "Project" class, so it needs some work.

Andy
64 bit integers make awesome timestamps for most practical purposes.
you have 19 digits to use there:
2021 01 03 16 17 30. 12345
year month day hour min sec subsecond

you can cram all that into just a few lines in a timestamp class.
they work nicely in taking differences, sorting by, etc.
Topic archived. No new replies allowed.