In class where we learn C++, I was given an assignment to make a class "date". Now, there is a specific function that I am required to make but I really do not have idea how to approach this. Members of class are day, month and year. Function takes some integer that represents days, and is supposed to set a new date, that comes after that many days. For example, if date is (DD-MM-YY) 20.01.2015, and we pass as an argument 15, new date is 04.02.2015, the problem is that I have to consider how many days each month has(considering February has 28 days), and if argument is too big, that we pass into next year, create an exception that prints how many days are there until next year(considering year has 365 days). That is, if the date is 20.12.2010, and argument is greater than 11, it should print 11.
My attempt was using while, where I declared at the beginning that int k=0; and where argument of function is a, than I used while(k!=a), but body of the function got really confusing because I used just too many if conditions. Another thing that I tried is to overlap operator++ and that surely gives me simpler function, because than there is only one for loop inside it, but I am not solving the problem, because in that overlapped operator function I am still using many if conditions.
Is there some elegant way to do this? Code and explanation would be great! Thank you!
Simply identify what you need and then create it, like
static unsigned int Date::days_of_month(const Month month, const unsigned int year);
void Date::operator+=(const unsigned int days);
+= could look like
void Date::operator+=(const unsigned int days){
increase current day by days
check if current day too large
if so, increase month (and maybe year)
repeat until day legal
}
Concept is clear? Haven't build in your output on purpose to give you something to do, after all, it's an exercise. Also wrote this in pseudo-code on purpose for the same reason. Try to create some code and if you really can't proceed, I'll add actual code.
const int m_daysInMonth[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 }; // first for index offset (no "zero" month)
class date {
public:
int days=20, month=11, year=2012;
void addDays(int daysNum)
{
int n_days = days, n_month = month; //new result. not saved, if there is an exception
while (daysNum > 0)
{
int daysToNextMonth = m_daysInMonth[n_month] - n_days + 1; //days before needs to change motn index
if (daysToNextMonth < daysNum) // change month
{
daysNum -= daysToNextMonth;
n_month++;
if (n_month > 12)
{
int daysLeft = m_daysInMonth[month] - days ;
n_month = month + 1;
while (n_month <= 12)
{
daysLeft += m_daysInMonth[n_month];
n_month++;
}
throw daysLeft;
}
n_days = 1; // start of the month
}
else // set day in the month
{
n_days += daysNum;
daysNum = 0;
}
}
days = n_days;
month = n_month;
}
};
Related
I'm attempting to create a date and time class using inheritance.
The parent class, Date, has variables month, day, and year.
The Date derived class, DateTime, has the same variables but with hour, minute, and second added. The DateTime instance, when created, must be passed a Date instance and with optional parameters hour, minute, and second. The Date parameter is a requirement. If the optional parameters are not passed, default values of 0 will be applied.
Is there a more efficient way to implement this? I feel like it is tedious to re-set the parameters by retrieving them using a function in the Date instance for the new DateTime instance.
DateTime::DateTime(Date passDate){
day = passDate.getDay();
month = passDate.getMonth();
year = passDate.getYear();
hour = 0;
minute = 0;
second = 0;
}
DateTime::DateTime(Date passDate, int hourSet){
day = passDate.getDay();
month = passDate.getMonth();
year = passDate.getYear();
hour = hourSet;
minute = 0;
second = 0;
}
DateTime::DateTime(Date passDate, int hourSet, int minuteSet){
day = passDate.getDay();
month = passDate.getMonth();
year = passDate.getYear();
hour = hourSet;
minute = minuteSet;
second = 0;
}
You can call parent class constructor and default parameter values to make your code much more concise:
DateTime::DateTime(const Date& passDate, int hourSet = 0, int minuteSet = 0):
Date(passDate) {
hour = hourSet;
minute = minuteSet;
second = 0;
}
You can use default constructor parameters in order to have a single constructor.
DateTime::DateTime(Date passDate, int hourSet=0, int minuteSet=0, int secondSet=0) {
day = passDate.getDay();
month = passDate.getMonth();
year = passDate.getYear();
hour = hourSet;
minute = minuteSet;
second = secondSet;
}
If any of the hourSet=0, minuteSet or secondSet parameters are omitted, they will automatically be replaced with 0.
You need to provide copy constructor and assignment operator in both classes with proper validation of input values.
With that you just need to implement getters/setters for both base and derived.
Let's say we're developing an API for other programmers. Our API has a Date object for them to use, and we want to limit what values the month, day, and year can be to valid values, such as 1-12 for the month, 1-31 for the day, and 1900-2014 for the year. So to do this, we create separate Month, Day, and Year objects, all of which are passed to Date's constructor, which we call like so:
Date date(Month::Jan(), Day(1), Year(1980));
In order to ensure that Month can only be 1-12, we can create separate functions for each month, each of which returns a month object corresponding to that month, and to ensure that no one can create a month with the wrong value, we make Month's constructor private:
class Month {
public:
static Month Jan () { return Month(1);}
static Month Feb () { return Month(2);}
static Month Mar () { return Month(3);}
static Month Apr () { return Month(4);}
static Month May () { return Month(5);}
static Month Jun () { return Month(6);}
static Month Jul () { return Month(7);}
static Month Aug () { return Month(8);}
static Month Sep () { return Month(9);}
static Month Oct () { return Month(10);}
static Month Nov () { return Month(11);}
static Month Dec () { return Month(12);}
private:
Month (int n) : monthNum (n) {}
int monthNum;
};
However, for Day and Year, we can't have function names that only contain numbers like Year::1997() and we want this format to be intuitive to client developers, so syntaxes like Year::year1997() are out. Plus, we don't want to manually code a function for every possible year. Let's say years go back significantly far enough that this would be a problem, like back to 1900, for instance. So we'll stick with the Day(1) or Year(1997) format.
Given this, what's a good way to ensure that the constructed Day and Year can only return the range of values we want? One way is to throw an exception if invalid values are entered:
class Day {
public:
Day (int d) : dayNum(d) {
if(d <= 0 || d >= 31) {
throw "Invalid day";
}
}
private:
int dayNum;
};
But this generates an error during runtime, not during compile time, and we're building this for developers to use, so we want them to know as soon as possible when they've done something wrong, such as putting an invalid day or year (e.g. day 32 or year 3000). What's an effective way to ensure clients can only create Day or Year objects with valid values, without waiting until program execution to notify them?
Template may be an option. Check out this
I'm writing a program, in which I have some competitors, which are defined by structure. I also have a date structure.
struct date{ int d; int m; int y;};
I must sort competitor by their age, and I have no idea how to get age of competitors, to compare it.
I also tried this:
void age(tekmovalec comp){
#define _CRT_SECURE_NO_WARNINGS
time_t theTime = time(NULL);
struct tm *aTime = localtime(&theTime);
int day = aTime->tm_mday;
int month = aTime->tm_mon + 1; // Month is 0 - 11, add 1 to get a jan-dec 1-12 concept
int year = aTime->tm_year + 1900;
int age1, age2;
if(comp.rojDat.m > month){
age1=year-comp.rojDat.y-1;
age2=(12-month) + comp.rojDat.m;
}else{
age1=year-comp.rojDat.y;
age2=12-comp.rojDat.m;
}
int age3 = age1*12 + age2;
comp.age=age3;
}
But it returns error that localtime is unsafe.
As you want to sort by date, you may want to take a look at std::sort. For comparison, you need to write a function comp that compares 2 competitors (you need just to compare their ages, using basic comparations between days, months and years).
bool comp(competitor a, competitor b){
if(a.age.y < b.age.y)
return true;
else if(a.age.y == b.age.y && a.age.m < b.age.m)
return true;
else if(a.age.y == b.age.y && a.age.m == b.age.m && a.age.d < b.age.d)
return true;
else
return false;
}
Note that this is not the best implementation (actually it is pretty messy), but it's purpose is to give you a hint, not to be used as it is.
Another way to achive this is to overload comparison operators for competitors.
There is no need for localtime. You do not need age; what you need is a way to compare age. To determine which of us is older, we do not need to know what year this is, all we need to know is which of us was born earlier.
Write a function that compares two birthdates:
bool operator<(const date &A, const date &B)
{
...
}
Then use that to build a function that compares two competitors, then use that to build a function that sorts competitors.
instead of localtime() which can cause issues (not thread safe), you can use localtime_r() which should not have warnings :
struct tm *localtime_r(const time_t *restrict timer, struct tm *restrict result);
struct tm mytime; // use this instead of aTime
localtime_r(&theTime, &myTime)
int day = myTime.tm_mday;
int month = myTime.tm_mon + 1; // Month is 0 - 11, add 1 to get a jan-dec 1-12 concept
int year = myTime.tm_year + 1900;
This might also be localtime_s()
I presume you are using Visual studio. _CRT_SECURE_NO_WARNINGS needs to be a preprocessor definition (i.e. Seen before any #includes or code)
Right click on the project, get the 'Properties' menu and find the C/C++ preprocessor definitions and put it thre.
To actually compare times, it might be easier if you use mktime after transforming your dat struct into a tm, but you'll have trouble if anyone was born before 1970.
See here
For some reason, when I use the destructor for my Update class, a debug assertion fail message displays...
here is my Update class with some code omitted for brevity. Placed in a header file:
using namespace std;
class Update
{
private:
int day, month, year;
static const int FIELD_SIZE = 3, DEFAULT_DAY = 12, DEFAULT_MONTH = 12,
DEFAULT_YEAR = 1999, DAYS_IN_MONTH = 30, MONTHS_IN_YEAR = 12, DAYS_IN_YEAR = 365;
int * date;
public:
static int dateUpdate;
Update(int D, int M, int Y)
{
day = D;
if (day < 1 || day > DAYS_IN_MONTH)
day = DEFAULT_DAY;
month = M;
if (month < 1 || month > MONTHS_IN_YEAR)
month = DEFAULT_MONTH;
year = Y;
if (year < 1)
year = DEFAULT_YEAR;
date = new int [FIELD_SIZE];
date[0] = day, date[1] = month, date[2] = year;
dateUpdate++;
}
~Update()
{
delete [] date;
dateUpdate--;
}
};
and here is my tester class in a cpp file:
#include <iostream>
#include "Update.h"
int Update::dateUpdate = 0;
int main()
{
Update u1(29, 12, 2000);
u1.Update::~Update();
return 0;
}
I've read through other questions involving debug assertion failures but something tells me a debug assertion failure can occur in various ways. As a result, I have little clue as to why the error message is displaying for my code... Is there something wrong with my destructor as I suspect at the moment? Thank you so much for your help in advance!
The problem is because you are calling destructor explicitly:
u1.Update::~Update();
this way it is called twice causing undefined behaviour, I suppose delete [] date; is called twice, the second time on alreade freed memory.
Another problem in your code is that you are using bare pointer for you array:
int * date;
this is actually quite low level programming style in C++ and can cause lots of problems. You should implement class copy constructor and assignment operator (*) that will allocate new date array when your Update class will be copied, otherwise you will have again problems with multiple date pointer deletions.
The best way is to use vector like
std::vector<int> date;
(*) I think good link where rule of three (or since C++11 rule of five) that applies here is explained: Rule-of-Three becomes Rule-of-Five with C++11?
You should change this line:
date[0] = day, date[1] = month, date[2] = year;
To:
date[0] = day;
date[1] = month;
date[2] = year;
You are using the comma operator, which returns the result of the last expression. This is not the same as how the comma operates in an initialization.
Also, in your main function, you do not need to explicitly call the destructor.
Your date method can't handle January 31 nor December 31.
You can access the parameters of the function directly instead of making a copy in the function. For example: day = D; is not needed; access the parameter directly: if ((D < 1) ....
If you used unsigned integers you would not need to check for negative numbers. I've never experienced a negative day, month or year in my life.
Since this is C++ and not Java or C#, you don't need to dynamically allocate variables. So rather than using int * date you could use int date[3].
I am having a hard time with two functions. Here are the project instructions:
Assignment:
Write a program which keeps track of the number of roaches in two adjacent houses for a number of weeks. The count of the roaches in the houses will be determined by the following:
The initial count of roaches for each house is a random number between 10 and 100.
Each week, the number of roaches increases by 30%.
The two houses share a wall, through which the roaches may migrate from one to the other. In a given week, if one house has more roaches than the other, roaches from the house with the higher population migrate to the house with the lower population. Specifically, 30% of the difference (rounded down) in population migrates.
Every four weeks, one of the houses is visited by an exterminator, resulting in a 90% reduction (rounded down) in the number of roaches in that house.
Here's my code:
#include <iostream>
#include <cmath>
using namespace std;
int house, increase, roaches, moreRoaches, fewerRoaches, filthyBeasts, change; // My variables for my four functions
int initialCount(int house);
int weeklyIncrease(int increase);
double roachesMigration(int moreRoaches, int fewerRoaches, int change);
int exterminationTime (int filthyBeasts);
// My four function prototypes
int main()
{
int houseA, houseB;
houseA = initialCount(houseA); //Initializing the initial count of House A.
houseB = initialCount(houseB); //Initializing the initial count of House B.
int week = 0;
for (week = 0; week < 11; week++) // My for loop iterating up to 11 weeks.
{
houseA = weeklyIncrease(houseA);
houseB = weeklyIncrease(houseB);
cout << "For week " << week << ", the total number of roaches in House A is " << houseA << endl;
cout << "For week " << week << ", the total number of roaches in House B is " << houseB << endl;
if((houseA > houseB)) // Migration option 1
{
roachesMigration(moreRoaches, fewerRoaches, change);
}
else if((houseB > houseA)) // Migration option 2
{
roachesMigration(moreRoaches, fewerRoaches, change);
}
if ((week + 1) % 4 == 0) // It's extermination time!
{
if ((rand() % 2) == 0) // Get a random number between 0 and 1.
{
houseB = exterminationTime(houseB);
}
else
{
houseA = exterminationTime(houseA);
}
}
}
return 0;
}
int initialCount(int house) // Initializing both houses to random numbers between 10 and 100.
{
int num;
num = (rand() % 91) + 10;
return num;
}
int weeklyIncrease(int increaseHouses) // Increasing the roaches in both houses by 30% weekly.
{
int increase = 0;
increase = (increaseHouses * .3) + increaseHouses;
return increase;
}
double roachesMigration(int moreRoaches, int fewerRoaches, int change)
{
more -= change;
fewer += change;
change = ((more - fewer) * .3);
return change;
}
int exterminationTime(int filthyBeasts) // Getting rid of the filthy little beasts!
{
filthyBeasts = (filthyBeasts * .1);
return filthyBeasts;
}
The issues are with the migration and extermination functions. My code runs fine, but at weeks 4 and 8, the randomly selected house should get exterminated, and the number of roaches in that house should be 90% less than the previous week. What do you guys think I should do to correct these issues? I really need all the help I can get!
Regarding this line:
roachesMigration(change);
change is not declared in your main function, hence the error. Also, roachesMigration function expects 3 parameters and not 1.
The variable change is not a global variable, but appears inside main (so it has no meaning inside main).
Your roachesMigration fonction is declared with three formal arguments (without default values), but you use it with one actual argument.
Ask your compiler to give you all the warnings and to produce debugging information (g++ -Wall -g on Linux). Improve the code till you get no warnings.
Learn to use a debugger (e.g. gdb on Linux).
Have fun.
Depending on the instructor, you will get zero marks for this code, even if you can get it to work perfectly! This is because you have not used any object orientated design in building your code. In C++, that means classes.
What sort of object do you need for this problem. A house!
What sort of attribute should your house have? Roaches!
So something like this:
class cHouse
{
int MyRoachCount;
...
};
If you start fresh, like this, you will find things start to fall neatly into place.
One possible way to handle the migration is like this pseudocode:
// compute size of migration
count = migration(houseA, houseB)
if (houseA < houseB)
add count to houseA
subtract count from houseB
else
add count to houseB
subtract count from houseA