0

Date.h

#include <string>

#ifndef DATE_H_
#define DATE_H_

class Date
{
public:
    static const unsigned int monthsPerYear{12};
    explicit Date(unsigned int d = 1, unsigned int m = 1, unsigned int y = 1900);
    std::string toString() const;
private:
    unsigned int day;
    unsigned int month;
    unsigned int year;
    unsigned int checkDay(unsigned int ) const;
};


#endif /* DATE_H_ */

Date.cpp

#include <iostream>
#include <sstream>
#include <stdexcept>
#include <array>
#include "Date.h"

using namespace std;

Date::Date(unsigned int d, unsigned int m, unsigned int y) : day{checkDay(d)}, month{m}, year{y} {
    if ( month < 1 || month > monthsPerYear ) {
        throw invalid_argument("wrong entry for month");
    }
}

string Date :: toString() const {
    ostringstream output;
    output << day << ":" << month << "/" << year;
    return output.str();
}

unsigned int Date :: checkDay(unsigned int testDay) const {
    static const array<unsigned, monthsPerYear + 1> daysPerMonth{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    if (testDay <= daysPerMonth[month] && testDay > 0) {
        return testDay;
    }
    return testDay;
}

main.cpp

#include <iostream>
#include "Date.h"

using namespace std;

int main()
{
    Date d2;
    cout << d2.toString() << endl;
    return 0;
}

i get nothing in the output console.

hnefatl
  • 5,860
  • 2
  • 27
  • 49
munish
  • 4,505
  • 14
  • 53
  • 83
  • 2
    Instead of creating a `toString` member function, why don't you overload `operator<<`? So you can simply do `cout << d2 << '\n';` – Some programmer dude Feb 10 '18 at 15:48
  • 1
    You also have *undefined behavior* because you use `month` before it has been initialized in the `checkDay` function. – Some programmer dude Feb 10 '18 at 15:51
  • 1
    In future please present your MCVE as a single file (as I show in my answer, but better) so that we don't have to merge it ourselves when plugging it into a compiler. – Lightness Races in Orbit Feb 10 '18 at 16:07
  • Use `int`, not `unsigned int`. Using unsigned numbers breaks your error checking; for example, `month < 1` will never be true (unless it's zero), because if someone passes a negative number to your constructor, it will have been converted to a positive number by the point you perform the check. – Christian Hackl Feb 10 '18 at 16:58

2 Answers2

3

I can't see anything wrong with this other than the UB that Some programmer dude identified, and I do get output (after transforming your snippets into a single-file testcase).

You can fix the UB by making checkDay take both day and month:

unsigned int checkDay(unsigned int, unsigned int) const;

and:

Date::Date(unsigned int d, unsigned int m, unsigned int y) : day{checkDay(d, m)}, month{m}, year{y} {

and:

unsigned int Date :: checkDay(unsigned int testDay, unsigned int testMonth) const {
    static const array<unsigned, monthsPerYear + 1> daysPerMonth{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    if (testDay <= daysPerMonth[testMonth] && testDay > 0) {
        return testDay;
    }
    return testDay;
}

Alternatively initialise month before calling the function (you'll have to declare month before day too, then) but I think the solution above has better symmetry given what the function does. I'd actually consider making checkDay a static member function now too.

Then it should work reliably.

Of course, for a non-learning program, you would be using boost::gregorian::date. :)

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
1

See initilization list order. The order of the variables in your class declaration dictates the order of assignment in the constructor. Simply arrange month to come before day in your class declaration:

private:
unsigned int month;
unsigned int day;
  • 2
    Then flip the initialisations around to get rid of the compiler warning. – Lightness Races in Orbit Feb 10 '18 at 15:57
  • actually i just did that and it worked, and yes need to flip around for compiler waring – munish Feb 10 '18 at 16:09
  • @munish Yes but if you look at my answer you'll see that there is a better way that results in a superior design. You should never have to alter your data layout or external API to work around strange designs like you have now. That makes for a fragile codebase. – Lightness Races in Orbit Feb 10 '18 at 16:27