C++ Member Functions - c++

I am trying to write a simple program that records the date. This program uses a Struct called Date. Within the Struct is a parameterized constructor Date.
The constructor also makes sure the date is roughly valid (makes sure months are between 1 and 12, and days are between 1 - 31). A later assignment addresses the issues with this type of validation.
Also within the Struct is an add_day function. This is where I am having issues. I cannot seem to call the struct variables to the function to add the day.
struct Date
{
int y, m, d;
public:
Date(int y, int m, int d);
void add_day(int n);
int month()
{
return m;
}
int day()
{
return d;
}
int year()
{
return y;
}
};
/// main program calls the struct and add day function with parameters.
int main()
{
Date today(1978, 6, 26);
today.add_day(1);
keep_window_open();
return 0;
}
// Function definition for the Constructor. Checks values to make sure they
are dates and then returns them.
Date::Date(int y, int m, int d)
{
if ((m < 1) || (m > 12))
cout << "Invalid Month\n";
if ((d < 1) || (d > 31))
cout << "Invalid Day\n";
else
y = y;
m = m;
d = d;
cout << "The date is " << m << ',' << d << ',' << y << endl;
// This function will accept the integers to make a date
// this function will also check for a valid date
}
void Date::add_day(int n)
{
// what do I put in here that will call the variables in Date to be
// modified to add one to day or d.
};

You can refer to the member variables of a class inside its member functions simply by naming them, e.g.:
void Date::add_day(int n)
{
d += n;
}
Here, d would refer to the int d member variable that you declared on top of your snippet:
struct Date
{
int y, m, d;
// ...
}
However, it is the shadowing of the member variables that is probably confusing you. Also, please note that you have other design issues and several ways that you can improve your code. Take a look at this version for some inspiration:
#include <iostream>
#include <stdexcept>
class Date
{
int year_, month_, day_;
public:
explicit Date(int year, int month, int day)
: year_(year), month_(month), day_(day)
{
if (month_ < 1 || month_ > 12)
throw std::logic_error("Invalid Month");
if (day_ < 1 || day_ > 31)
throw std::logic_error("Invalid Day");
}
void add_days(int days) { /* ... */ }
int year() const { return year_; }
int month() const { return month_; }
int day() const { return day_; }
};
std::ostream & operator<<(std::ostream & os, const Date & date)
{
return os << date.year() << '-' << date.month() << '-' << date.day();
}
int main()
{
Date date(1978, 6, 26);
date.add_days(1);
std::cout << date << '\n';
return 0;
}

The member variables are accessible in the member functions and constructor implicitly by referring to them with their name (y, m, d), or explicitly with this pointer (this->y, this->m, this->d).
So for example to add a day:
void Date::add_day(int n)
{
d += n; // Modifies the 'd' member variable
// ... below here we must handle what
// happens when the number of days exceeds t
// he number of days in the particular month.
};
You also have a issue in the constructor. Because the argument variables to the constructor share the same names with the member variables. For example:
m = m;
d = d;
With these assignments, the compiler will assume you mean to assign the local argument variable to the local argument argument variable. So you are actually not assigning the member variable any value at all. One solution is to to explicitly specify them as follows:
this->m = m;
this->d = d;
The same goes for the y variable.

Related

How can I change the parameters of a default constructor?

I have a class called Date that controls the date.
I have a constructor Date(). If this constructor is uninitialized, a default date will be put in its place by a private, static data member called default_.
I have initialized default_ in Date.cpp as follows:
Date Date::default_{1, Month::January, 1900};
Where the first argument is an int for the day, second is an enum class called Month for the month, and third is an int for the year.
When I run this program, I can print the date and it shows the correct default date that has been set by default_.
Question:
I want to be able to change the default date with a function:
setDefaultDate(int day, Month month, int year)
How can I do this? I have tried to implement setDefaultDate() as follows but it is not working:
void Date::setDefaultDate(int day, Month month, int year)
{
default_ = {day,month,year};
}
Code:
Date.h:
#ifndef DATE_H
#define DATE_H
// date.h
// class Date declaration
#include <cassert>
#include <iostream>
using namespace std;
enum class Month
{
January = 1,
February,
March,
April,
May,
June,
July,
August,
September,
October,
November,
December
};
class Date
{
public:
// return the day of the month
int day () const;
// return the month of the year
Month month () const;
// return the year
int year () const;
Date();
static void setDefaultDate(int day, Month month, int year);
private:
int day_;
Month month_;
int year_;
static Date default_;
};
// standalone function for printing the date
void printDate(const Date& date);
#endif
Date.cpp:
// date.cpp
// Implementation of the Date class
#include "date.h"
int Date::day() const
{
return day_;
}
Month Date::month() const
{
return month_;
}
int Date::year() const
{
return year_;
}
// Note, this standalone function is not part of the Date class
void printDate(const Date& date)
{
cout << date.day() << "/"
// cast to an integer to allow the month to be sent to the stream
<< static_cast<int>(date.month()) << "/"
<< date.year()
<< endl;
}
Date Date::default_{1, Month::January, 1900};
void Date::setDefaultDate(int day, Month month, int year)
{
default_ = {day,month,year};
}
Date::Date()
{
day_ = default_.day();
month_ = default_.month();
year_ = default_.year();
}
Example
int main()
{
auto date_1 = Date{};
date_1.setDefaultDate(29, Month::September, 2020);
printDate(date_1);
}
Expected output:
29/9/2020
Actual Output:
1/1/1900
It compiles, but the setDefaultDate() function is not working, and the default date is being outputted that was declared in default_.
Let's step through your main line by line:
auto date_1 = Date{};
What will this do? It will call Date::Date, which will read all of the values from default_ into date_1. At this point default_ is 1/1/1900 and date_1 now is the same. Then
date_1.setDefaultDate(29, Month::September, 2020);
will change default_ and default_ only. I'm not sure why you expect date_1 to change here, maybe because you've called it like a non-static member function? You probably meant to change the default date before reading from it. You can do it like so:
int main()
{
// call it like static function
Date::setDefaultDate(29, Month::September, 2020);
// Only then read from it.
auto date_1 = Date{};
// prints 29/9/2020
printDate(date_1);
}
Your setDefaultDate() method sets only the value of default_, which main() has already made a copy of when calling the Date() constructor for the date_1 object. Changing the value of default_ afterwards has no effect whatsoever on the value of date_1. When you print date_1, you output the value it was initialized with. Changing the value of default_ will only have an effect on subsequent Date objects that you create afterwards.
If you want to change the value of date_1, you need to either:
call setDefaultDate() before calling Date():
int main()
{
Date::setDefaultDate(29, Month::September, 2020);
Date date_1;
printDate(date_1); // 29/9/2020
}
add non-static methods to mutate the values of a Date object. You should also add a non-default constructor that can take a user-specified date as input, eg:
class Date
{
public:
Date();
Date(int initialDay, Month initialMonth, int initialYear);
...
void setDay (int newValue);
void setMonth (Month newValue);
void setYear (int newValue);
...
};
Date::Date() :
Date(default_.day_, default_.month_, default_.year_)
{
}
Date::Date(int initialDay, Month initialMonth, int initialYear) :
day_(initialDay),
month_(initialMonth),
year_(initialYear)
{
}
void Date::setDay (int newValue)
{
day_ = newValue;
}
void Date::setMonth (Month newValue)
{
month_ = newValue;
}
void Date::setYear (int newValue)
{
year_ = newValue;
}
...
int main()
{
Date date_1;
printDate(date_1); // 1/1/1900
date_1.setDay(29);
date_1.setMonth(Month::September);
date_1.setYear(2020);
printDate(date_1); // 29/9/2020
date_1 = Date(9, Month::September, 2020);
printDate(date_1); // 9/9/2020
Date date_2(31, Month::December, 2020);
printDate(date_2); // 31/12/2020
Date::setDefaultDate(1, Month::April, 2020);
Date date_3;
printDate(date_3); // 1/4/2020
}
I will show you a modified version of your code that should do what you need to, if I understood it correctly. I changed your code a bit, in order to use a single file
java is not C++, C++ is not java. And static things in C++ goes not the java way. Maybe you are used to that.
One thing is in C++ you can set up the defaults running code just outside of main() and outside the class as
...
}; // class Date{}
int Date::default_day = 1;
int Date::default_month = 1;
int Date::default_year = 1900;
void printDate(const Date& date);
void setDefaultDate(int, int, int);
int main(void)
{
...
And so you have the first set of defaults loaded.
And if you do it inside main() it compiles but the linker will
complain about all 3 of them as unresolved.
for setDefaultDate() you can just declare it as Date's friend
friend void setDefaultDate(int, int, int);
a convenient and common alternative to PrintDate() is to declare another friend to Date, as
friend ostream& operator<<(ostream&, Date&);
An example using your code
Program shows
just a date at start (should use defaults 1900,1,1)
printDate()
d: 1 m: 1 y: 1900
Now sets default to 1901/3/2
printDate()
d: 2 m: 3 y: 1901
Now declared new Date instance as d3(2019,8,7)
printDate()
d: 7 m: 8 y: 2019
Now print all 3 dates using "<<" operator, redefined for Date class
printDate using insertion operator '<<'
year is 1900 month is 1 year is 1900
printDate using insertion operator '<<'
year is 1901 month is 3 year is 1901
printDate using insertion operator '<<'
year is 2019 month is 8 year is 2019
main() is
int main(void)
{
cout << "\njust a date at start (should use defaults 1900,1,1)\n";
Date d1;
printDate(d1);
cout << "\nNow sets default to 1901/3/2\n";
setDefaultDate(2, 3, 1901);
Date d2;
printDate(d2);
cout << "\nNow declared new Date instance as d3(2019,8,7)\n";
Date d3(2019, 8, 7);
printDate(d3);
cout << "\nNow print all 3 dates using \"<<\" operator, redefined for Date class\n";
cout << d1 << d2;
cout << d3;
return 0;
}
Code uses printDate() and also the overloaded << as an alternative to printDate(). I left two cout for the 3 Date just to show that you can chain the printing as with any other cout call.
The program sets the defaults before and inside main()
I added a 2nd constructor that accepts day, month and year as arguments
the complete example
#include <iostream>
using namespace std;
class Date
{
private:
int year_;
int month_;
int day_;
public:
int year() const { return year_; };
int month() const { return month_; };
int day() const { return day_; };
// default as Date d;
Date() :
year_(default_year), month_(default_month), day_(default_day) {};
// as Date d(2020,9,8)
Date(int y, int m, int d) :
year_(y), month_(m), day_(d){};
friend void setDefaultDate(int, int, int);
friend ostream& operator<<(ostream&, Date&);
private:
static int default_year;
static int default_month;
static int default_day;
}; // class Date{}
int Date::default_day = 1;
int Date::default_month = 1;
int Date::default_year = 1900;
void printDate(const Date& date);
void setDefaultDate(int, int, int);
int main(void)
{
cout << "\njust a date at start (should use defaults 1900,1,1)\n";
Date d1;
printDate(d1);
cout << "\nNow sets default to 1901/3/2\n";
setDefaultDate(2, 3, 1901);
Date d2;
printDate(d2);
cout << "\nNow declared new Date instance as d3(2019,8,7)\n";
Date d3(2019, 8, 7);
printDate(d3);
cout << "\nNow print all 3 dates using \"<<\" operator, redefined for Date class\n";
cout << d1 << d2;
cout << d3;
return 0;
}
void printDate(const Date& date)
{
cout << "\nprintDate()\n" <<
" d: " << date.day() <<
" m: " << date.month() <<
" y: " << date.year()
<< endl;
};
void setDefaultDate(int day, int month, int year)
{
Date::default_day = day;
Date::default_month = month;
Date::default_year = year;
};
ostream& operator<<(ostream& out, Date& date)
{
cout << "\nprintDate using insertion operator '<<'\n" <<
"\tyear is " << date.year_ <<
" month is " << date.month_ <<
" year is " << date.year_ <<
endl;
return out;
};
No religion here. I compiled it just under MSVC 19.27

How to use array with pointer?

I am new to programming and an trying to create an array with a series of records in and then have the programme accept input and finally print out the contents of the list.
I am having trouble recording the values of some of the variables in my addRecord() function as the output of the code below is the following:
constructor called
-1:-1 Eat lunch
-1:-1 Watch TV
destructor called
Why am I missing the call to L1.addRecord(5, 30, "Make dinner"); completely and why aren't the times coming through (they are coming through as -1 which is set in the constructor)?
Thank you
#include <iostream>
#include <string>
using namespace std;
class Record {
private:
int hour;
int minute;
string todo;
public:
Record()
{
hour = -1;
minute = -1;
todo = "N/A";
}
void setData(int hour, int minute, const char* td);
void setData(Record& e);
void printRecord();
};
class List
{
private:
Record* recordArr;
int maxRecords;
int actualRecordCount;
public:
List(int maxRecords);
List(List& s) {
actualRecordCount = s.actualRecordCount;
maxRecords = s.maxRecords;
recordArr = new Record[maxRecords];
for (int i = 0; i < actualRecordCount; i++)
{
recordArr[i].setData(s.recordArr[i]);
}
std::cout << "copy constructor called." << std::endl;
}
~List();
bool addRecord(int hour, int minute, const char* todo);
void printList();
};
///////////////////////////
void Record::setData(int hour, int minute, const char* td)
{
hour = hour;
minute = minute;
todo = td;
}
void Record::setData(Record& e)
{
hour = e.hour;
minute = e.minute;
todo = e.todo;
}
void Record::printRecord()
{
std::cout << hour << ":" << minute << " " << todo << std::endl;
}
List::List(int maxRecords)
: maxRecords(maxRecords)
{
actualRecordCount = 0;
recordArr = new Record[maxRecords];
std::cout << "constructor called" << std::endl;
}
List::~List()
{
std::cout << "\ndestructor called";
delete[] recordArr;
}
bool List::addRecord(int hour, int minute, const char* todo)
{
Record newRecord; // create new Record
newRecord.setData(hour, minute, todo); //assign values
if (actualRecordCount >= maxRecords) // array full
{
return false;
}
else
{
recordArr[actualRecordCount] = newRecord; // put new Record into the array of Entry
actualRecordCount++; // increment Entry count
return true;
}
}
void List::printList()
{
for (int i = 0; i < actualRecordCount; i++)
{
recordArr[i].printRecord();
cout << endl;
i++;
}
}
int main() {
List L1(20);
L1.addRecord(2, 30, "Eat lunch");
L1.addRecord(5, 30, "Make dinner");
L1.addRecord(7, 30, "Watch TV");
L1.printList();
}
void Record::setData(int hour, int minute, const char* td)
{
hour = hour;
"hour" is the name of a parameter to this setData() method. hour=hour;, therefore, sets this parameter to itself. This accomplishes absolutely nothing, whatsoever. Same for other two assignments that follow.
Your obvious intent here is to initialize the class that happens to have members with the same name. When different things have the same name in C++ there's a complicated set of rules that choose which "thing" the name represents. These rules are the same on the left and the right side of the = operator, so both of these hours end up referring to the same object: the parameter to this class method.
You can simply rename the parameters to the method:
void Record::setData(int hourArg, int minuteArg, const char* tdArg)
{
hour = hourArg;
and so on. Or, if you wish to keep the parameter names the same, make things more explicit:
this->hour=hour;
The other error is here
void List::printList()
{
for (int i = 0; i < actualRecordCount; i++)
{
recordArr[i].printRecord();
cout << endl;
i++;
}
}
You have i++ twice.
One problem is that your Record::setData function with three arguments doesn't actually set the hour and minute fields of the class object! This is caused by your use of arguments with the same name as the class members, which (IMHO) is bad coding style. So, in the following code, your first two assignments just replace the argument values with themselves:
void Record::setData(int hour, int minute, const char* td)
{
hour = hour; // This and the following line are self-assignments to the arguments
minute = minute; // given and, as such, are effectively doing nothing!
todo = td; // This, however, is OK, because there is no ambiguity.
}
To fix this, either add an explicit this-> reference to the targets:
void Record::setData(int hour, int minute, const char* td)
{
this->hour = hour;
this->minute = minute;
todo = td;
}
Or (much better, in my opinion) give the first two arguments non-ambiguous names:
void Record::setData(int in_hour, int in_minute, const char* td)
{
hour = in_hour;
minute = in_minute;
todo = td;
}

C++ comparing variables as an object

I'm trying to compare two variables and the type of these variables are "Time". I can't seem to use the == / != function for these.
#include<iostream>
#include "Stock.h"
using namespace std;
void Stock::setShares(int d, int m, int y, int h, int mts, double p, int vol, double val)
{
date.setDate(d, m, y);
time.setTime(h, mts);
price = p;
value = val;
volume = vol;
}
Date Stock::getDate() const
{
return date;
}
Time Stock::getTime() const
{
return time;
}
This is in my main program:
Time t1, t2;
for (int i = 1; i < counter; ++i)
{
if (V1.at(i).getPrice() == highestPrice)
{
time2 = V1.at(i).getTime;
if (time2 != time1)
{
cout << time2;
}
}
}
How can I compare time1 & time2? I'm trying to avoid printing duplicate values of time in my program. V1 is a vector loaded with data from Stock object.
Check first whether == or != operator is overloaded for type Time. You must provide your own meaning to operators which you are gonna to use in your code for user-defined types else you will get compiler errors.
something like below,
class Time
{
public:
bool operator==(Time const & t1) const
{
return this.hour == t1.hour && this.min==t1.min;
}
private:
int min;
int hour;
};
In order to be able to answer your question completely, it would be necessary to know the details of the type "Time". Since you talk about comparing two objects, let's assume it is class.
If it was simple class like this:
class Time {
public:
int getValue();
void setValue(int value);
private:
int value;
}
You would need to use getValue method:
if( t1.getValue() == t2.getValue())
If you want to compare the objects directly, you need to overload the necessary operators:
bool operator==(const Time& anotherTime) const {
return (anotherTime.getValue()==this->getValue());
}

nullptr can't use in valarray

Why can't use nullptr in the constructor function?( the function name: Wine) When i try to do this, the program will break down and no any error report maybe because i don't the reason for that.
#ifndef WINE_H_
#define WINE_H_
#include<iostream>
#include<string>
#include<valarray>
using std::string;
using std::valarray;
template<typename T1, typename T2>
class Pair //member of the wine
{
private:
T1 a;
T2 b;
public:
T1 & first(){ return a; }
T2 & second(){ return b; }
T1 first()const{ return a; }
T2 second()const{ return b; }
Pair(const T1 & aval, const T2 & bval) :a(aval), b(bval){}
Pair(){}
};
typedef valarray<int>ArrayInt;
typedef Pair<ArrayInt, ArrayInt>PairArray;
class Wine
{
private:
string name;
PairArray bt;
int years;
public:
Wine();
Wine(const char * a, int y,int b[], int c[]); //no problem
Wine(const char * a, int y); //here is that problem function
void GetBottles(); //no problem
void Show()const; //no problem
int Sum(){ return bt.second().sum(); }
};
Wine::Wine(const char * a, int y) :name(a), years(y), bt(ArrayInt(0, y), ArrayInt(0, y)){}
**//When I am trying to use nullptr to instead 0 in the ArrayInt(0,y),the whole program will break down during work.**
Wine::Wine(const char * a, int y, int b[], int c[]) :bt(ArrayInt(b, y), ArrayInt(c, y))
{
name = a;
years = y;
}
Wine::Wine() :bt(ArrayInt(),ArrayInt())
{
name = "null";
years = 0;
}
void Wine::GetBottles()
{
std::cout << "Please input the years and the bottles\n";
for (int i = 0; i < years; i++)
{
std::cout << "input the year: ";
(std::cin >> bt.first()[i]).get();
std::cout << "input the bottles";
(std::cin >> bt.second()[i]).get();
}
}
void Wine::Show()const
{
using std::cout;
using std::endl;
for (int i = 0; i < years; i++)
{
cout << bt.first()[i] << '\0' << bt.second()[i] << endl;
}
}
#endif
#include<iostream> //test part
#include"wine.h"
int main(void)
{
using std::cin;
using std::cout;
using std::endl;
cout << "Enter name of wine: ";
char lab[50];
cin.getline(lab, 50);
cout << "Enter number of years: ";
int yrs;
cin >> yrs;
Wine holding(lab, yrs);
holding.GetBottles();
holding.Show();
return 0;
}
Thank your for your help!
This is a funny one. The reason why it breaks in one example, but not another is following:
There are two different constructors for std::valarray (more than that, but those two matter):
valarray( const T& val, std::size_t count ); // 1
valarray( const T* vals, std::size_t count ); // 2
When you use 0 (valarray(0, y)) you are calling the first version - creating an array of y elements, where every element is initialized to 0.
But when you are calling it with nullptr, you are calling the second version of it - trying to initialize your new array with a copy from an array pointed to by the first argument to the constructor. But your first argument is nullptr, and any attempt to use at as an array triggers undefined behavior, and program crashes.

cyclic negative number generation in C++

I have requirement as follows.
I have to generate increment negative numbers from -1 to -100 which is used a unique id for a request. Like it should be like this: -1, -2, -3, ...-100, -1, -2, and so on. How can I do this effectively? I am not supposed to use Boost. C++ STL is fine. I prefer to write simple function like int GetNextID() and it should generate ID. Request sample program on how to do this effectively?
Thanks for your time and help
int ID = -1;
auto getnext = [=] mutable {
if (ID == -100) ID = -1;
return ID--;
};
Fairly basic stuff here, really. If you have to ask somebody on the Interwebs to write this program for you, you should really consider finding some educational material in C++.
I love the functor solution:
template <int limit> class NegativeNumber
{
public:
NegativeNumber() : current(0) {};
int operator()()
{
return -(1 + (current++ % limit));
};
private:
int current;
};
Then, you can define any generator with any limit and use it:
NegativeNumber<5> five;
NegativeNumber<2> two;
for (int x = 0; x < 20; ++x)
std::cout << "limit five: " << five() << "\tlimit two: " << two() << '\n';
You can also pass the generator as parameter to another function, with each funtor with its own state:
void f5(NegativeNumber<5> &n)
{
std::cout << "limit five: " << n() << '\n';
}
void f2(NegativeNumber<2> &n)
{
std::cout << "limit two: " << n() << '\n';
}
f5(five);
f2(two);
If you don't like the template solution to declare the limit, there's also the no-template version:
class NegativeNumberNoTemplate
{
public:
NegativeNumberNoTemplate(int limit) : m_limit(limit), current(0) {};
int operator()()
{
return -(1 + (current++ % m_limit));
};
private:
const int m_limit;
int current;
};
Using as argument to a function works in the same way, and it's internal state is transfered as well:
void f(NegativeNumberNoTemplate &n)
{
std::cout << "no template: " << n() << '\n';
}
NegativeNumberNoTemplate notemplate(3);
f(notemplate);
I hope you don't want to use it with threading, they're not thread safe ;)
Here you have all the examples; hope it helps.
Something like.... (haven't compiled)
class myClass
{
int number = 0;
int GetValue ()
{
return - (number = ((number+1) % 101))
}
}
Even a simple problem like this could lead you to several approximations, both in the algorithmic solution and in the concrete usage of the programming language.
This was my first solution using C++03. I preferred to switch the sign after computing the value.
#include <iostream>
int GetNextID() {
// This variable is private to this function. Be careful of not calling it
// from multiple threads!
static int current_value = 0;
const int MAX_CYCLE_VALUE = 100;
return - (current_value++ % MAX_CYCLE_VALUE) - 1;
}
int main()
{
const int TOTAL_GETS = 500;
for (int i = 0; i < TOTAL_GETS; ++i)
std::cout << GetNextID() << std::endl;
}
A different solution taking into account that the integer modulo in C++ takes the sign of the dividend (!) as commented in the Wikipedia
#include <iostream>
int GetNextID() {
// This variable is private to this function. Be careful of not calling it
// from multiple threads!
static int current_value = 0;
const int MAX_CYCLE_VALUE = 10;
return (current_value-- % MAX_CYCLE_VALUE) - 1;
}
int main()
{
const int TOTAL_GETS = 50;
for (int i = 0; i < TOTAL_GETS; ++i)
std::cout << GetNextID() << std::endl;
}