C++: proper format to initialize derived and base along - c++

I have made a date class that can hold the month, the day, and the year. But now I have a problem.
I've used this date class with inheritance to store for example the dateOfBirth for person(receptionist, passenger, and etc) (A hotel) by the Ctor of person(in fact using Ctor of date class in the initialization list of person), but now I don't know what is the format which I should use in main to initialize a person?! Is there anyway that I can do it directly in main at all? Sorry I'm beginner. Any help appreciated.
Here's some parts of my code:
class date {
int month = 1;
vector<int>month_days{ 31,31,31,31,31,31,30,30,30,30,30,29 };
int day = 1;
int year = 1300;
//---------------------member functions:
public:
date(int m = 1, int d = 1, int y = 1300) {
if (m>0 && m <= 31) month = m;
if (d>0 && d <= 31) day = d;
if (y>0 && y <= 3000) year = y;
}
//some other code...
};
class person:public date {
protected:
string m_name;
string m_familyName;
string m_idNumber;
//---------------------member functions:
public:
person(string name, string familyName, string idNumber, date dateOfBirth)
: m_name(name),m_familyName(familyName),m_idNumber(idNumber),date(dateOfBirth)
{
}
//some other code...
};
This is what I typed in main and I know that it can't do the job:
person a("Michael", "Deoran", "05174084", (4,17,1998));
I checked the stored date for object "a" and its date returns 1,1,1300, nevertheless, I don't know what can do the job too.
(By the way, the reason I defined a date, separate from person, is that I overloaded the operator- in it to calculate the stay time of passenger)

All you need to do is change parentheses to braces (that is for the code to compile, not to be also well-designed and not producing -Wreorder warnings):
person a("Michael", "Deoran", "05174084", {4, 17, 1998});
- list initialization.
The version with parentheses is equivalent to (comma operator):
person a("Michael", "Deoran", "05174084", 1998);
I would think twice before providing default values for the parameters. You probably don't need them.

Related

Changing date for certain amount of days function

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;
}
};

C++: Constructors: Parent class parameters and setting values in new instance

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.

Get age out of date structure

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

Debug assertion failed message

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].

Passing Private Variables in Classes - Why Is This Not Allowed?

I have this class:
class Date
{
public:
Date(); // Sets a date of January 1, 2000
Date(int mm, int dd, int yyyy); // Sets a date with the passed arguments; automatically converts two-digit years as being AFTER the year 2000
Date after_period_of ( int days ) const; // Elapses an arbitrary amount of time, and returns a new date
string mmddyy () const; // Returns date in MM/DD/YY format (1/1/00)
string full_date () const; // Returns date in full format (January 1, 2000)
string month_name () const; // Returns the name of the month as a string;
private:
int days_in_february(int yr);
int month;
int day;
int year;
};
When I try to pass private variable year as an argument into days_in_february, I get the following error message:
passing ‘const Date’ as ‘this’ argument of ‘int Date::days_in_february(int)’ discards qualifiers
days_in_february is called in after_period_of, like this:
Date Date::after_period_of (int days_elapsed) const
{
int new_month;
int new_year = year; // tried copying 'year' to get around this issue, but it did not help
int days_into_new_month;
int max_days_in_month[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } ;
max_days_in_month[1] = days_in_february(new_year);
and again in the same function:
if (new_month == 13)
{
new_month = 1;
new_year += 1;
max_days_in_month[1] = days_in_february(new_year);
}
days_in_february simply returns the number 28 or 29 based on year that is passed into it. It does not attempt to manipulate anything outside of its own block.
I have even tried to pass a non-programmed variable into it (days_in_february(2000)) and I get the same error.I've tried moving that function into the public domain, but that didn't fix the issue either.
Why is this happening?
Why am I not allowed to do this?
Inside after_period_of, you cannot access non-constant functions; in particular, you cannot access days_in_february. You can fix this by also declaring the latter function const.