Hy! This is my first question on this site. Sorry for my English, if I will make mistakes:(
So, my problem is the following. I have simple class Date.
class Date
{
public:
Date();
Date(unsigned short day, unsigned short month, unsigned short year);
Date(const Date &date);
unsigned short getDay();
unsigned short getMonth();
unsigned short getYear();
void setDay(unsigned short day);
void setMonth(unsigned short month);
void setYear(unsigned short year);
void printOnScreen()const;
friend
std::ostream& operator<< (std::ostream& out, const Date& date) {
out << date.day << "." << date.month << "." << date.year;
return out;
}
friend
bool operator<(const Date& a, const Date& b) {
if (a == b) {
return false;
}
if (a.year < b.year) {
return true;
}
if (a.month < b.month) {
return true;
}
if (a.day < b.day) {
return true;
}
return false;
}
friend
Date& operator-(Date& a) {
return a;
}
friend
Date operator-(const Date& a, const Date& b) {
return Date(
abs(a.day - b.day),
abs(a.month - b.month),
abs(a.year - b.year)
);
}
friend
bool operator==(const Date& date1, const Date& date2) {
return (
date1.day == date2.day &&
date1.month == date2.month &&
date1.year == date2.year
);
}
virtual ~Date();
private:
friend KeyHasher;
unsigned short day;
unsigned short month;
unsigned short year;
};
In my main function I call sort like in this example, and after it get the error.
auto dates = {
Date(1, 5, 2016),
Date(3, 2, 2015),
Date(3, 3, 2000),
Date(2, 1, 1991),
Date(1, 8, 2200),
Date(1, 8, 2200),
Date(1, 8, 2020),
Date(21, 9, 2016)
};
vector<Date> v1(dates);
sort(
v1.begin(),
v1.end(),
less<Date>()
);
What is wrong, I don't understand. Thank you for help.
Your operator < is indeed incorrect, use std::tie:
auto as_tuple(const Date& d) {
return std::tie(d.year, d.month, d.day);
}
bool operator<(const Date& lhs, const Date& rhs) {
return as_tuple(lhs) < as_tuple(rhs);
}
bool operator == (const Date& lhs, const Date& rhs) {
return as_tuple(lhs) == as_tuple(rhs);
}
Try to change your conditions like:
if (a.year < b.year)
return true;
else if (a.year > b.year)
return false;
else // a.year == b.year
{
if (a.month < b.month)
return true;
else if (a.month > b.month)
return false;
else // a.month == b.month
{
if (a.day < b.day)
return true;
else
return false;
}
}
Related
I'm building a numeric class to work with 1 to 8 bytes. The idea is: input the value by a string or a char*, then the program convert it to unsigned short, unsigned int or unsigned long, according to the string size (I've used stringstream to conversion, this part is ok). After the program separa the value in bytes, storing them in a vector<unsigned char>. To output the number, the program convert the vector<unsigned char> to unsigned short, unsigned int or unsigned long, according to the number of bytes and then convert to string.
The problem is: the program is storing/showing a value different to the inputed.
Here's the full code:
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned int uint;
typedef unsigned long ulong;
class Num
{
private:
vector<uchar> x;
ushort len;
template<typename T>
string str()
{
T val = 0;
for(ushort i = 0; i < len; i++)
{
val += x[i] * pow(256, i);
}
stringstream res;
res << val;
return res.str();
}
template<typename T>
void set(string a)
{
T val;
stringstream(a) >> val;
x.resize(0);
len = 0;
while(val > 255)
{
x.push_back((T)(val % 256));
len++;
val = (T)(val / 256);
}
len++;
for(ushort i = 0; i <= len / 2; i++)
{
uchar aux = x[i];
x[i] = x[len - 1 - i];
x[x.size() - 1 - i] = aux;
}
}
public:
Num()
{
x.resize(0);
len = 0;
}
Num(const Num& other)
{
*this = other;
}
friend bool operator>(const Num& l, const Num& r)
{
for(uchar i = l.len - 1; i >= 0; i--)
{
if(l.x[i] != r.x[i])
return (l.x[i] > r.x[i]);
}
}
friend bool operator<(const Num& l, const Num& r)
{
return r > l;
}
friend bool operator>=(const Num& l, const Num& r)
{
return !(l < r);
}
friend bool operator<=(const Num& l, const Num& r)
{
return !(l > r);
}
friend bool operator==(const Num& l, const Num& r)
{
return l >= r && l <= r;
}
friend bool operator!=(const Num& l, const Num& r)
{
return !(l == r);
}
Num& operator=(const string& l)
{
string a = l;
if(a.size() <= 4)
{
set<ushort>(a);
}
else if(a.size() <= 9)
{
set<uint>(a);
}
else
{
set<ulong>(a);
}
return *this;
}
Num& operator=(const char* l)
{
return (*this = string(l));
}
string get()
{
if(len == 0)
return "0";
if(len <= 2)
{
return str<ushort>();
}
else if(len <= 4)
{
return str<uint>();
}
else
{
return str<ulong>();
}
}
friend ostream& operator<<(ostream& os, Num& l)
{
return os << l.get();
}
friend istream& operator>>(istream& is, Num& l)
{
string x;
is >> x;
l = x;
return is;
}
};
int main()
{
Num x;
cout << "Entrada: ";
cin >> x;
cout << "Saida: "<< x << endl;
system("pause");
return 0;
}
The result can be:
Entrada: 572648319
Saida: 3136023423
I am trying to compile my code and I keep getting the error:
redefinition of 'SimpleDate::SimpleDate(int, int, int)
I think the error is usually because of not adding #ifndef, #define, and #endif but I did add those.
simple_date.h:
#ifndef SIMPLE_DATE_H
#define SIMPLE_DATE_H
#include <string>
class SimpleDate
{
int _year, _month, _day;
public:
// create a new 'SimpleDate' object with the given year, month, and day
// throws an invalid_argument error if the date is invalid
SimpleDate(int year, int month, int day) {};
// returns the current year
int year() const { return 0; };
// returns the current month
int month() const { return 0; };
// returns the current day of the month
int day() const { return 0; };
// return string formatted as year-month-day with day an month 0 prefixed
// i.e. 2000-01-01 is Jan 01, 2000
std::string to_string() const { return ""; };
// comparison operators
bool operator==(const SimpleDate& lhs) const { return true; };
bool operator!=(const SimpleDate& lhs) const { return true; };
bool operator> (const SimpleDate& lhs) const { return true; };
bool operator< (const SimpleDate& lhs) const { return true; };
bool operator>=(const SimpleDate& lhs) const { return true; };
bool operator<=(const SimpleDate& lhs) const { return true; };
// returns 'true' if current year is a leap year
bool is_leap() const { return true; };
// returns the day of the week; 0 = Sunday
// HINT: To calculate the day of the week, you need to have a known day. Use
// 1970-01-01 which was a Thursday. Make sure to reference where you found
// the algorithm or how you came up with it.
int wday() const { return 0; };
// returns the day of the year; Jan 1st = 1
int yday() const { return 0; };
// add one day to current date
SimpleDate& incr_day() { SimpleDate dd {2016, 1, 1}; };
SimpleDate& operator++() { SimpleDate dd {2016, 1, 1}; };
// add n day(s) to current date
SimpleDate& operator+=(int n) { SimpleDate dd {2016, 1, 1}; };
// subtract one day from current date
SimpleDate& decr_day() { SimpleDate dd {2016, 1, 1}; };
SimpleDate& operator--() { SimpleDate dd {2016, 1, 1}; };
// subtract n day(s) from current date
SimpleDate& operator-=(int n) { SimpleDate dd {2016, 1, 1}; };
// add one month to current date
SimpleDate& incr_month() { SimpleDate dd {2016, 1, 1}; };
// subtract one month from current date
SimpleDate& decr_month() { SimpleDate dd {2016, 1, 1}; };
// add one year to current date
SimpleDate& incr_year() { SimpleDate dd {2016, 1, 1}; };
// subtract one year from current date
SimpleDate& decr_year() { SimpleDate dd {2016, 1, 1}; };
// returns 'true' if current date is a Monday
bool is_monday() const { return true; };
// returns 'true' if current date is a Tuesday
bool is_tuesday() const { return true; };
// returns 'true' if current date is a Wednesday
bool is_wednesday() const { return true; };
// returns 'true' if current date is a Thursday
bool is_thursday() const { return true; };
// returns 'true' if current date is a Friday
bool is_friday() const { return true; };
// returns 'true' if current date is a Saturday
bool is_saturday() const { return true; };
// returns 'true' if current date is a Sunday
bool is_sunday() const { return true; };
};
#endif
simple_date.cpp:
#include "simple_date.h"
SimpleDate::SimpleDate(int year, int month, int day)
{
std::cout >> year;
if (year < 1970 || year > 2020)
{
throw invalid_argument("Don't care about years less than 1970 or greater than 2020");
}
else
{
_year = year;
}
if (month < 1 || month > 12)
{
throw invalid_argument("Not a real month");
}
else
{
_month = month;
}
if (day < 1 || day>31)
{
throw invalid_argument("Not a real day");
}
else if ((_month == 2 || _month == 4 || _month == 6 || _month == 9 || _month == 11) && day > 30)
{
throw invalid_argument("Not a real day for this month");
}
else if (_month == 2 && day == 29)
{
if (this.is_leap())
_day = day;
else
hrow invalid_argument("Not a real day for this month and year");
}
else
_day = day;
}
You defined the constructor in the header file, here:
SimpleDate(int year, int month, int day) {};
Those innocent-looking braces turned this declaration into a definition. And then compiler got very upset when it later encountered the real definition of this constructor. Just remove them:
SimpleDate(int year, int month, int day);
I had to write a program for my laboratory at college. In the program I want to compare two dates in the format day/month/year. I know how to do that,but without including the hour.For now I'm converting the date into days passed since year 0000 and simply compare these two values. The problem is my teacher told me to add hours and now I dont know how to compare this. Any suggestions? Present code bellow
.h File
class timee
{
int day;
int month;
int year;
int hour;
long int count;
public:
timee();
timee(int,int,int,int);
long int daysCount();
bool operator>(const timee &);
bool operator>=(const timee &);
bool operator<=(const timee &);
bool operator==(const timee &);
timee & operator=(const timee &);
timee & operator+=(int);
timee & operator-=(int);
long int operator-(timee &);
friend ostream & operator<<(ostream &, const timee &);
friend istream & operator>>(istream &, timee &);
};
Here the .cpp file
timee::timee():day(0),month(0),year(0),hour(0),count(0){}
timee::timee(int day,int month,int year,int hour):day(day),month(month),year(year),hour(hour)
{
count = daysCount();
}
/*calculating the number of days that have passed since year 0000*/
long int timee::daysCount()
{
int month_days[] = {0,31,59,90,120,151,181,212,243,273,304,334};
// calculate number of leap years.
int leapyears = year / 4;
if (isLeapYear(year) && month < 3)
{
// If this is a leap year
// And we have not passed Feburary then it does
// not count.....
leapyears --;
}
// convert year/month/day into a day count
count = year * 365 + month_days[month-1] + day + leapyears;
return count;
}
/*convering the date from days since year 0000 to year/month/day format */
timee timee::dateConversion()
{
int month_days[] = {0,31,59,90,120,151,181,212,243,273,304,334,365};
//calculate number of leap year
int leapyears = year / 4;
if (isLeapYear(year) && month < 3)
{
// If this is a leap year
// And we have not passed Feburary then it does
// not count.....
leapyears --;
}
//calculating year
year = (count-leapyears)/365;
for(unsigned int i = 0; i <= 12; i++)
{
if((count-leapyears)%365 > month_days[i])
{
month = i+1;
}
}
day = ((count-leapyears)%365)-month_days[month-1];
return *this;
}
bool timee::operator>(const timee &obj)
{
return count>obj.count;
}
bool timee::operator>=(const timee &obj)
{
//if((count>=obj.count) && (hour>=obj.hour)) return true;
//else if((count<=obj.count) && (hour>obj.hour))return false;
}
bool timee::operator<=(const timee &obj)
{
return count<=obj.count;
}
bool timee::operator==(const timee &obj)
{
return count==obj.count;
}
timee & timee::operator=(const timee &obj)
{
day=obj.day;
month=obj.month;
year=obj.year;
hour=obj.hour;
count=obj.count;
return *this;
}
timee & timee::operator+=(int value)
{
count+=value;
this->dateConversion();
return *this;
}
timee & timee::operator-=(int value)
{
count-=value;
this->dateConversion();
return *this;
}
long int timee::operator-(timee &obj)
{
return count - obj.count;
}
ostream & operator<<(ostream &os, const timee &obj)
{
os << "Date: " << obj.day << "." << obj.month << "." << obj.year << " Hour: " << obj.hour << " " << obj.count << endl;
return os;
}
istream & operator>>(istream &is, timee &obj)
{
cout << "Type day, month and year" << endl;
is >> obj.day >> obj.month >> obj.year >> obj.hour;
obj.daysCount();
return is;
}
There is one of my attempts to overload the >= operator. Please help.
count in your algorithm refers to the number of days passed since year 0.
Though, the smallest precision you should have now is not a day, but an hour. So you should simply create a variable totalHours being the number of hours passed since year 0.
//Calculate number of days since year 0
count = year * 365 + month_days[month-1] + day + leapyears;
//Convert to number of HOURS since year 0, and add additional hour
totalHours = count*24 + hour;
There are 3 possible relations between count and obj.count inside operator >=. Either count < obj.count or count == obj.count or count > obj.count. The same holds for hours and obj.hours. That gives 3 * 3 = 9 possible combinations. Write down what the result of the operator should be for each combination and then find the easiest way to express that in your code.
Note that you don't need to do this for each comparison operator. Typically you implement operator < and then define the others in terms of that one.
I have a program that asks the user to input to dates then it displays which one is more recent I've done it like this
if (year1>year2 || month1>month2 || day1>day2)
return -1;
if (year1<year2 || month1<month2 || day1<day2)
return +1;
but the output is not quite correct.
Here's a clean way to do it:
#include <tuple> // for std::tie
auto date1 = std::tie(year1, month1, day1);
auto date2 = std::tie(year2, month2, day2);
if (date1 == date2)
return 0;
return (date1 < date2) ? -1 : 1;
The comparisons of std::tie objects are lexicographical, so this returns -1 if date1 is less than date2, 0 if they are the same, and 1 if date1 is greater than date2.
You might be better off defining your own date type (or use boost::datetime).
struct Date
{
unsigned year;
unsigned month;
unsigned day;
};
bool operator<(const Date& lhs, const Date& rhs)
{
return std::tie(lhs.year, lhs.month, lhs.day) <
std::tie(rhs.year, rhs.month, rhs.day);
}
bool operator>(const Date& lhs, const Date& rhs) { .... }
bool operator==(const Date& lhs, const Date& rhs) { .... }
int date_cmp(const Date& lhs, const Date& rhs)
{
// use operators above to return -1, 0, 1 accordingly
}
You need a much more complicated check than that:
if (year1 > year2)
return -1;
else if (year1 < year2)
return +1;
if (month1 > month2)
return -1;
else if (month1 < month2)
return +1;
if (day1 > day2)
return -1;
else if (day1 < day2)
return +1;
return 0;
NOTE: Returning -1 for first is greater than second seems counter-intuititive to me, however I have followed the semantics provided by the OP.
This statement
if (year1>year2 || month1>month2 || day1>day2)
return -1;
tests if any one of the three conditions is true. So, if year1 is higher than year 2, or month1 is higher than month2. Lets stop there. Consider
year1 = 2013, month1 = 12, day1 = 31;
year2 = 2014, month2 = 1, day1 = 1;
We know that, infact, year2 is a higher value, but what happens is
is year1 > year2? no
ok, but is month1 > month2? yes
This makes it look like the first year is a higher value, but it's not, it just a higher month value.
As you get further into C++ you'll find that it's a good idea to try and adopt a convention of making all your comparisons use a single operator (< or >), when you reach a point where you are working with operators you'll understand why.
if (year2 < year1)
return 1;
// we reach this line when year1 <= year2
if (year1 < year2) // elimnate the < case
return -1;
// having eliminated both non-matches,
// we know that by reaching point that both
// dates have the same year. Now repeat for
// the month value.
if (month2 < month1)
return 1;
if (month1 < month2)
return -1;
// year and month must be the same, repeat for day.
if (day2 < day1)
return 1;
if (day1 < day2)
return -1;
return 0; // exact match
//You can try this
int lday,lmonth,lyear;
int nday,nmonth,nyear;
int lhour,lminute;
int nhour,nminute;
sscanf(New_Time,"%d-%d",&nhour,&nminute); //reads the numbers
sscanf(Last_Time,"%d-%d",&lhour,&lminute); //from the string
sscanf(New_Date,"%d-%d-%d",&nday,&nmonth,&nyear);
sscanf(Last_Date,"%d-%d-%d",&lday,&lmonth,&lyear);
//cout << "Last date: " << lday << "-" << lmonth << "-" << lyear <<endl;
//cout << "New date: " << nday << "-" << nmonth << "-" << nyear <<endl;
if(nyear>lyear)
return 0;
if(nyear==lyear) {
if(nmonth > lmonth)
return 0;
if (nmonth == lmonth) {
if(nday > lday)
return 0;
if (nday == lday) {
if( nhour > lhour)
return 0;
if( nhour == lhour) {
if(nminute>lminute) {
//cout << "new time >= last time" << endl <<endl;
return 0;
}
else return 1;
}
else return 1;
}
else return 1;
}
else return 1;
}
else return 1;
struct Day
{
int value;
explicit Day(int value)
{
this->value = value;
}
};
struct Month
{
int value;
explicit Month(int value)
{
this->value = value;
}
};
struct Year
{
int value;
explicit Year(int value)
{
this->value = value;
}
};
class Date {
public:
Date(Day newDay, Month newMonth, Year newYear)
{
_day = newDay.value;
_month = newMonth.value;
_year = newYear.value;
}
int GetYear() const {
return _year;
};
int GetMonth() const {
return _month;
};
int GetDay() const {
return _day;
};
private:
int _year;
int _month;
int _day;
};
bool operator < (const Date& lhs, const Date& rhs)
{
if (lhs.GetYear() == rhs.GetYear()) {
if (lhs.GetMonth() == rhs.GetMonth()) {
if (lhs.GetDay() == rhs.GetDay()) {
return false;
}
return lhs.GetDay() < rhs.GetDay();
}
return lhs.GetMonth() < rhs.GetMonth();
}
return lhs.GetYear() < rhs.GetYear();
};
I'm trying to do the exercises at the end of chapter 9 from Bjarne Stroustrup's book "Programming: Principles and Practice using C++". I copied most of this code from the book and only had to define the Date class' member functions add_day(), add_month(), add_year(), and overload the + operator for it to work with the Chrono::Date::Month enumeration.
My problem is that the program compiles, but crashes when I'm using the Chrono::Date::add_month() function in main(). add_month() is the only function that uses the overloaded + operator on the Month enumeration. The two other member functions (add_day() and add_year()) work fine when used in main(). When I'm doing exactly what add_month() does directly in main() (without using the function), it works fine.
The crash occurs at line 100 of Chrono.cpp with the error "Stack Overflow":
Date::Month& operator + (Date::Month& m, int n) {
Here's my code:
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 (working):
#include "Chrono.h"
int main() {
cout << Chrono::Date::jan + 1;
}
alternate main.cpp (compiling but crashing):
#include "Chrono.h"
int main() {
Chrono::Date date;
date.add_month(1);
}
P.S: std_lib_facilities.h defines vectors, strings and IOs. It's available here.
Date::Month& operator + (Date::Month& m, int n) {
return m + n;
}
It may not look obvious to you, but this is a recursive call. It keeps calling itself, without a terminal condition. Eventually, you fill up the stack by infinitely calling this function.