Wednesday, 21 August 2019

Chapter 9 // Exercise 15 - Principles & Practice Using C++

In this exercise I am using Visual Studio Community 2017 and the header file "std_lib_facilities.h" which can be found here:

http://www.stroustrup.com/Programming/PPP2code/std_lib_facilities.h


Chapter 9 // Exercise 15



Refine the Money class by adding a currency (given as a constructor argument). Accept a floating-point initializer as long as it can be exactly represented as a long int. Don't accept illegal operations. For example, Money*Money doesn't make sense, and USD1.23+DKK5.00 makes sense only if you provide a conversion table defining the conversion factor between U.S. dollars (USD) and Danish kroner (DKK).

...I literally have no idea what he wants me to do here. So we add a currency in the constructor, say GBP as a string along with a floating-point value. We've already been doing that but now we have to to do a check to ensure that it will fit in a long int. A long int is 32 bits in size and a double is 64 bits. (If anyone is interested, in a programming interview I was asked about the size of a struct and it contained all the fundamental types, so it's worth learning the sizes of each type). A float is 32 bits so perhaps we should change m_dollars to a float instead. The worst that would happen if we didn't is that we would lose some bits as they would get truncated to fit. I don't understand what he means by illegal operations though. Does he mean, don't allow Money*Money in the initialiser? It wouldn't compile anyway in the code as there is no definition for it. And for USD1.23+DKK5.00 where is this called? By the programmer writing the code or is it an argument passed to the program via input from the user? If it was the latter, I suppose you would take it in as a string and parse each value, then pass the currency and value to the money class to be constructed with that value. You can construct new classes at run time but it's far beyond what's been taught in the book so far. This is not well constructed exercise.

main.cpp

//----------------------------------//
// main.cpp
//----------------------------------//

//INCLUDES//
#include "moneyClass.h"

int main()
{
 Money gbp(c_GBP, 3.34);
 gbp.printMoney();

 Money usd(c_USD, 786.789);
 usd.printMoney();

 gbp + usd;
 usd + gbp;

 cout << "\nPress any key to quit...";
 _getch();

 return 0;
}

moneyClass.h

//----------------------------------//
// moneyClass.h
//----------------------------------//
// for calculations involving money
//----------------------------------//
#ifndef _MONEYCLASS_H_
#define _MONEYCLASS_H_

//INCLUDES//
#include <iostream>
#include <iomanip>
#include <conio.h>

using namespace std;

//----------------------------------//
// ENUM: Currencies
//----------------------------------//
enum Currencies
{
 c_GBP,
 c_USD
};

//----------------------------------//
// CLASS: Money
//----------------------------------//
class Money
{
public:
 Money(Currencies currency, float amount);
 ~Money();

 void printMoney();

 Currencies getCurrency()    { return m_currency; }
 long int   getOutPutMoney() { return m_outputMoney; }
 double     getInputMoney()  { return m_inputMoney; }

private:
 //variables//
 Currencies m_currency;
 long int m_outputMoney; //cents
 double m_inputMoney; //dollars

};

//OPERATOR OVERLOADS//
void operator+(Money& money1, Money& money2);
ostream& operator<<(ostream& os, Money& money);

#endif // !_MONEYCLASS_H_


moneyClass.cpp

//----------------------------------//
// moneyClass.cpp
//----------------------------------//
// for calculations involving money
//----------------------------------//

//INCLUDES//
#include "moneyClass.h"

//VARIABLES//
double gbp2usd = 1.26;
double usd2gbp = 0.79;

Money::Money(Currencies currency, float amount) 
{
 m_currency = currency;
 m_inputMoney = amount;
}

Money::~Money() {}

//print output as dollars
void Money::printMoney()
{
 m_outputMoney = round(m_inputMoney * 100.0f);

 switch (m_currency)
 {
 case c_USD:
  cout << "-----USD----" << endl;
  cout << "Dollars: $" << fixed << setprecision(2) << m_inputMoney << endl;
  cout << "Cents: " << fixed << setprecision(0) << m_outputMoney << endl;
  break;
 case c_GBP:
  cout << "-----GBP----" << endl;
  cout << "Pounds: £" << fixed << setprecision(2) << m_inputMoney << endl;
  cout << "Pennies: " << fixed << setprecision(0) << m_outputMoney << "p" << endl;
  break;
 default:
  cout << "Bad output";
  break;
 }
}

//OPERATOR OVERLOADS//

//add currencies together - converts money if not the same
void operator+(Money& money1, Money& money2)
{
 cout << "\n";
 if (money1.getCurrency() == money2.getCurrency())
  //currencies are the same, no conversion needed, just add
  cout << fixed << setprecision(2) << money1.getInputMoney() + money2.getInputMoney();
 else if (money1.getCurrency() == c_GBP && money2.getCurrency() == c_USD)
 {
  //return pounds
  cout << fixed << setprecision(2) << "£" << (money2.getInputMoney() * usd2gbp) + money1.getInputMoney() << endl;
 }
 else if (money1.getCurrency() == c_USD && money2.getCurrency() == c_GBP)
 {
  //return dollars
  cout << fixed << setprecision(2) << "$" << (money2.getInputMoney() * gbp2usd) + money1.getInputMoney() << endl;
 }
}

//print out money
ostream& operator<<(ostream& os, Money& money)
{
 switch (money.getCurrency())
 {
 case c_GBP:
  return os << "\n£" << money.getInputMoney() << endl;
  break;
 case c_USD:
  return os << "\n$" << money.getInputMoney() << endl;
  break;
 default:
  return os << "Bad output";
  break;
 }
}

I'm still not entirely sure if this is what he wanted us to do but it takes in a currency (and you can add more to the enum, just provide converters in moneyClass.cpp). I even added some operator overloads to print out the money and add different currencies together.

Tuesday, 20 August 2019

Chapter 9 // Exercise 14 - Principles & Practice Using C++

In this exercise I am using Visual Studio Community 2017 and the header file "std_lib_facilities.h" which can be found here:

http://www.stroustrup.com/Programming/PPP2code/std_lib_facilities.h


Chapter 9 // Exercise 14



Design and implement a Money class for calculations involving dollars and cents where arithmetic has to be accurate to the last cent using the 4/5 rounding rule (.5 of a cent rounds up; anything less than .5 rounds down). Represent a monetary amount as a number of cents in a long int, but input and output as dollars and cents, e.g., $123.45. Do not worry about amounts that don't fit into a long int.

main.cpp

//----------------------------------//
// main.cpp
//----------------------------------//

//INCLUDES//
#include <iostream>
#include <iomanip>
#include <conio.h>

using namespace std;

int main()
{
 double cents, dollars;
 cout << "$";
 cin >> dollars;

 cents = dollars * 100.0f;
 cents = round(cents);

 cout << "Dollars: $" << fixed << setprecision(2) << dollars << endl;
 cout << "Cents: " << fixed << setprecision(0) << cents << endl;

 system("pause");
 return 0;
}

My first attempt I felt I had not done it correctly as it seemed a little too simple. It was the rounding rule that got me. Where did we need the code to round? When converting dollars to cents you just multiply it by 100. Then divide it by 100 to convert it back to dollars. I'm guessing he means that if someone inputs $2.298 he wants that figure rounded to $2.30 then stored as cents in a long int. I created a simple rounding program as seen above. This does exactly what he specifies. I then re-jigged it into the class format below as we expand on it in the next few exercises.

main.cpp

//----------------------------------//
// main.cpp
//----------------------------------//

//INCLUDES//
#include "moneyClass.h"

int main()
{
 Money money;
 money.menu();

 return 0;
}

moneyClass.h

//----------------------------------//
// moneyClass.h
//----------------------------------//
// for calculations involving dollars
// and cents
//----------------------------------//
#ifndef _MONEYCLASS_H_
#define _MONEYCLASS_H_

//INCLUDES//
#include <iostream>
#include <iomanip>
#include <conio.h>

using namespace std;

//----------------------------------//
// CLASS: Money
//----------------------------------//
class Money
{
public:
 Money();
 ~Money();

 void menu();

private:
 void getInput();
 void printDollars();

 void convertToCents();

 //variables//
 long int m_cents;
 double m_dollars;

};

#endif // !_MONEYCLASS_H_


moneyClass.cpp

//----------------------------------//
// moneyClass.cpp
//----------------------------------//
// for calculations involving dollars
// and cents
//----------------------------------//

//INCLUDES//
#include "moneyClass.h"

Money::Money() {}

Money::~Money() {}

//main menu
void Money::menu()
{
 cout << "-----Money Class----" << endl;

 getInput();
 convertToCents();
 printDollars();
}

//get input as $0.00
void Money::getInput()
{
 double input;
 cout << "Please enter dollars: \n$";
 cin >> input;

 m_dollars = input;
}

//convert dollars to cents
void Money::convertToCents()
{
 //100 cents == $1
 m_cents = round(m_dollars * 100.0f);
}

//print output as dollars
void Money::printDollars()
{
 cout << "Dollars: $" << fixed << setprecision(2) << m_dollars << endl;
 cout << "Cents: " << fixed << setprecision(0) << m_cents << endl;

 //return to main menu
 system("pause");
 system("CLS");
 m_cents = m_dollars = 0;
 menu();
}

A lot of people seem to go a bit crazy when it comes to rounding. The standard library provides a function called round() which generally adheres to the 4/5 rounding rule so there's no need to implement it yourself. Also, I used a float at first to store the currency however it came with some issues to I switched to a double to store the initial dollars in. I then just manipulated the output using cout functions to make them specific to certain decimal points.

Monday, 19 August 2019

Chapter 9 // Exercise 13 - Principles & Practice Using C++

In this exercise I am using Visual Studio Community 2017 and the header file "std_lib_facilities.h" which can be found here:

http://www.stroustrup.com/Programming/PPP2code/std_lib_facilities.h


Chapter 9 // Exercise 13



Design and implement a rational number class, Rational. A rational number has two parts: a numerator and a denominator, for example, 5/6 (five-sixths, also known as approximately 0.83333). Look up the definition if you need to. Provide assignment, addition, subtraction, multiplication, division and equality operators. Also, provide a conversion to double. Why would people want to use a Rational class?

This one took me a while as I planned out exactly how to go around it. Bjarne made the exercise vague enough for it to be interpreted a number of ways (pun intended). This was not a hard exercise, however it did make me think about class structure and the time was spent rearranging functions. This isn't perfect as I've omitted quite a few error checks, which you obviously wouldn't do if the public were to use this. 

I probably spent more time than is necessary on formatting but I just wanted it to look pretty. We could have gone the whole calculator route as well and done a new version which took in a string of say "4:5 * 7:5" with ':' denoting the separator as we'd need that sign for division however I instead left it for the user to just implement what they'd like in code.

This kind of class would be very useful to people like me who get flustered when they see things like "5/16ths of inch". I've never really been that great at working with fractions so something that works it out for you is quite useful. However, you could just use Google...like I do.

As I've used quite a few files, here is the full code drop:
https://github.com/l-paz91/principles-practice/tree/master/Chapter%209/Exercise%2013

EDIT 03/12/2019 - The link above is a link to a new version that I completed today. To be honest I can't even remember what I did now for the original but it sounds stupidly complicated.

I found the following sites useful:
Rational Numbers
Finding Greatest Common Divisor

Tuesday, 25 June 2019

Blog Update // A New Adventure

It's been a while since this blog has seen some action. I promised myself I would finally finish P+P over last summer however, I started stressing about my dissertation and enjoyed being free for a while. Then I started the final year of my degree and well, it's the hardest year for a reason. I'm happy to announce that I have just graduated with a First with distinction.

In other news, I have received a job offer at a Microsoft game studio as a software engineer intern. I'll be working in the game engine department which I'm very happy about as that was the route I wanted to go. It's strange, all I've ever known is working minimum wage jobs. I was a waitress from 13-18, then a receptionist from 18-27 (and briefly a flight attendant at 22) and I always thought dream jobs were for people in movies or TV shows. I dropped out of college and a career to me was moving up from receptionist to head receptionist and maybe even getting on the management track. Then I decided to go back to school and get a degree. Now I'm actually getting paid to create video games; I still can't fully comprehend it.

I start in a couple of weeks and I'm terrified. Because I never did any programming before starting the course I can't stop thinking about how unprepared I am compared to youngsters these days who have been modding games since since they were kids. When I was kid we had a Windows 95 PC with a staggering 250mb hard drive and, wait for it, 32 whole megabytes of RAM. I remember having boxes of floppy disks filled with midi files from my favourite games. MP3's took too long to download so midi files had to do. Funny story, the first MP3 I ever downloaded was "Eyes on Me" from Final Fantasy 8 and it was 5mb. It took 2 and half hours to download and my mum kept having a go at me because she wanted to use the phone...ah the nineties.

Anyway, I will get Principle and Practice finished as I kind of need to be an excellent C++ programmer now. I also have a lot of projects that I want to start and I have some plans for this blog. My dissertation on the Super Nintendo went well and I ended up creating a program that converts bitmap images to SNES format as well as writing a short introduction on how to program the SNES. That's going to get cleaned up and hopefully this site can help others start their retro game-dev journey. The SNES fascinates me; as does Assembly programming and I'm trying my best to learn x86. 

After P&P, I'll be eventually posting full tutorials on how to create 2D and 3D games engines using DirectX 9 and 11 with C++. DX9 may be depreciated now but it still works on Windows 10 and it's a fantastic way to ease yourself into custom engine creation as 11 and 12 are headaches. Then, I'll be rounding it out with some Android tutorials. I've begrudgingly learnt Java (and I hate every second of using it) and hope that some apps will help bring in a little bit of extra money to pay the rent. I may switch to C# and Xamarin though, just because I hate Java that much.

The end goal eventually is to move back to my home town and start up my own games studio using my own engine; but we're talking 10 year goals here. I may even start Let's Playing as indie horror games (especially the terrible ones) are just the best thing. 

But anyway, ramble over. This blog has not been forgotten and I've already got a lot of exercises scheduled as I want to get several done so there are no long gaps again. I move in a couple of days but hopefully things should start up properly in August; I may start sooner though. Thanks again and happy programming.

Monday, 24 September 2018

Chapter 9 // Exercise 12 - Principles & Practice Using C++

In this exercise I am using Visual Studio Community 2017 and the header file "std_lib_facilities.h" which can be found here:

http://www.stroustrup.com/Programming/PPP2code/std_lib_facilities.h


Chapter 9 // Exercise 12



Change the representation of a Date to be the number of days since January 1, 1970 (known as day 0), represented as a long int, and re-implement the functions from section 9.8. Be sure to reject dates outside the range we can represent that was (feel free to reject days before day 0, i.e no negative days).

dateclass.h
//dateclass.h
#ifndef _DATECLASS_H_
#define _DATECLASS_H_

#include "std_lib_facilities.h"

enum class Month
{
 jan = 1, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec
};

enum class Day
{
 monday = 1, tuesday, wednesday, thursday, friday, saturday, sunday
};

//forward declaration
Month returnMonth(int month);
Day returnDay(int day);

//9.8 The Date Class
class Date
{
public:
 Date();
 ~Date();
 Date(int y, Month m, int d);  //check for valid date & initialise

 //non-modifying operations:
 int day() const { return d; };
 Month month() const { return m; }
 int year() const { return y; }

 //modifying operations:
 void add_day(int n);
 void add_month(int n);
 void add_year(int n);

private:
 int y;
 Month m;
 int d;

 bool lastDay = false;
 bool endYear = false;
};

//helper functions
bool is_date(int y, Month m, int d);   //true for valid date
bool leapyear(int y);     //true if y is leap year

Day findDayOfWeek(const Date& d);   //returns the day for the given date
Day next_workday(const Date& d);   //retrieves the next work day
int week_of_the_year(const Date& d);   //returns the number of the week in the year
int howManyDaysSince(const Date& d);   //returns how many days since the start of the year
long int daysSince(const Date& date1, const Date& date2); //returns how many days between two given dates
void printDay(const Day& day);    //prints out day in written form

ostream& operator<<(ostream& os, Date& d);
istream& operator>>(istream& is, Date& dd);

bool operator==(const Date& a, const Date& b);
bool operator!=(const Date& a, const Date& b);

//to help with finding day for any given date
struct stringInt
{
 int monthDay;
 int key;
};

#endif // !_DATECLASS_H_


dateclass.cpp
//dateclass.cpp

#include "dateclass.h"

vector<stringInt> monthKey
{
 { 3, 1 },{ 4, 2 },{ 5, 3 },{ 6, 4 },{ 7, 5 },{ 8, 6 },{ 9, 7 },{ 10, 8 },{ 11, 9 },{ 12, 10 },{ 1, 11 },{ 2, 12 }
};
vector<stringInt> dayKey
{
 { 7, 0 },{ 1, 1 },{ 2, 2 },{ 3, 3 },{ 4, 4 },{ 5, 5 },{ 6, 6 }
};

//default Date Constructor
Date::Date() 
{
 y = 2001;
 m = Month::jan;
 d = 1;
}

//deconstructor
Date::~Date() {}

//Date Constructor - initialise the day
Date::Date(int y, Month m, int d)
{
 //check that y m d is a valid date
 if (!is_date(y, m, d))
  cout << "Error, invalid date." << endl;
 else
 {
  //if date is valid, initalise the date
  Date::y = y;
  Date::m = m;
  Date::d = d;
 }

 return;
}

//increment date by n days
void Date::add_day(int n)
{
 //if day goes above 31, increase month, set day to 1
 //if month goes above 12, increase year, set month to 1
 for (int i = 0; i < n; ++i)
 {
  //wrap days
  if (Date::d == 31)
   lastDay = true;
  Date::d = (Date::d == 31) ? 1 : ++Date::d;  //if day is equal to 31, make it 1, otherwise ++

  if (lastDay)
  {
   //wrap month
   lastDay = false;
   int mon = (static_cast<int>(Date::m) == 12) ? 1 : (static_cast<int>(Date::m) + 1); //if month is equal to 12, make it 1, otherwise ++
   Date::m = returnMonth(mon);
   if (static_cast<int>(Date::m) == 12)
    endYear = true;

   if (endYear)
   {
    //just increase year by one
    endYear = false;
    ++Date::y;
   }

  }

 }
}

void Date::add_month(int n)
{
 for (int i = 0; i < n; ++i)
 {
  //if month is equal to 12, make it 1, otherwise ++
  int mon = (static_cast<int>(Date::m) == 12) ? 1 : (static_cast<int>(Date::m) + 1);
  Date::m = returnMonth(mon);
  if (static_cast<int>(Date::m) == 12)
   endYear = true;

  if (endYear)
  {
   //just increase year by one
   endYear = false;
   ++Date::y;
  }
 }
}

void Date::add_year(int n)
{
 for (int i = 0; i < n; ++i)
  ++Date::y;
}

//switch to return correct type of Month
Month returnMonth(int month)
{
 switch (month)
 {
 case 1:
  return Month::jan;
  break;
 case 2:
  return Month::feb;
  break;
 case 3:
  return Month::mar;
  break;
 case 4:
  return Month::apr;
  break;
 case 5:
  return Month::may;
  break;
 case 6:
  return Month::jun;
  break;
 case 7:
  return Month::jul;
  break;
 case 8:
  return Month::aug;
  break;
 case 9:
  return Month::sep;
  break;
 case 10:
  return Month::oct;
  break;
 case 11:
  return Month::nov;
  break;
 case 12:
  return Month::dec;
  break;
 default:
  cout << "Bad month" << endl;
 }
}

//switch to return correct day
Day returnDay(int day)
{
 switch (day)
 {
 case 7:
  return Day::sunday;
  break;
 case 1:
  return Day::monday;
  break;
 case 2:
  return Day::tuesday;
  break;
 case 3:
  return Day::wednesday;
  break;
 case 4:
  return Day::thursday;
  break;
 case 5:
  return Day::friday;
  break;
 case 6:
  return Day::saturday;
  break;
 default:
  cout << "Bad day" << endl;
 }
}

void printDay(const Day& day)
{
 switch (day)
 {
 case Day::sunday:
  cout << "Sunday\n";
  break;
 case Day::monday:
  cout << "Monday\n";
  break;
 case Day::tuesday:
  cout << "Tuesday\n";
  break;
 case Day::wednesday:
  cout << "Wednesday\n";
  break;
 case Day::thursday:
  cout << "Thursday\n";
  break;
 case Day::friday:
  cout << "Friday\n";
  break;
 case Day::saturday:
  cout << "Saturday\n";
  break;
 default:
  cout << "Bad day" << endl;
 }
}

//true for valid date
bool is_date(int y, Month m, int d)
{
 //check that y is valid
 if (y < 1900 || y > 2018)
 {
  cout << "Error, invalid year." << endl;
  return false;
 }

 //check that m is valid
 if (m < Month::jan || m > Month::dec)
  return false;

 //check that d is valid
 if (d <= 0)
  return false; //d must be positive

 int daysInMonth = 31;  //most months have 31 days

 switch (m)
 {
  case Month::feb:
   //if leapyear, make it 29, if not make it 28
   daysInMonth = (leapyear(y)) ? 29 : 28;
   break;
  case Month::apr: case Month::jun: case Month::sep: case Month::nov:
   daysInMonth = 30; //the rest have 30 days
   break;
 }

 if (daysInMonth < d)
  return false;

 return true;
}

//this was wrong in previous chapters, I've realised this now and changed it
//new version of leapyear
bool leapyear(int y)
{
 //if century year, must be divisible by 400
 if (y % 400 == 0)
  return true;
 
 //if normal year and divisible by 4
 if (y % 4 == 0)
  return true;

 //else not leap year
 else
  return false;
}

//find day of the week for any year using Zeller's Rule
Day findDayOfWeek(const Date& d)
{
 int day, month, year, century;
 
 //get day
 day = d.day();

 //get key for month
 for (int i = 0; i < monthKey.size(); ++i)
 {
  if (monthKey[i].monthDay == static_cast<int>(d.month()))
   month = monthKey[i].key;
 }

 //get last two digits of year
 year = d.year() % 100;
 if (month == 11 || month == 12)
  year -= 1;

 //get the century - first 2 digits of year
 string y = to_string(d.year());
 char y1 = y.at(0);
 char y2 = y.at(1);
 string y3;
 y3 += y1;
 y3 += y2;
 century = stoi(y3);

 int f = d.day() + ((13 * month - 1) / 5) + year + (year / 4) + (century / 4) - (2 * century);
 day = f % 7;

 //get which day it is
 for (int i = 0; i < dayKey.size(); ++i)
 {
  if (day == dayKey[i].key)
   day = dayKey[i].monthDay;
 }

 return returnDay(day);
}

//retrieves the next work day
Day next_workday(const Date& d)
{
 //find the current day
 Day current = findDayOfWeek(d);

 //find next day
 Date nextDay(d);
 nextDay.add_day(1);
 Day next = findDayOfWeek(nextDay);
 while (next == Day::saturday || next == Day::sunday)
 {
  nextDay.add_day(1);
  next = findDayOfWeek(nextDay);
 }

 return next;
}

//returns how many days since the start of the year
int howManyDaysSince(const Date& d)
{
 int day = d.day();
 int month = static_cast<int>(d.month());
 cout << "Month: " << month << endl;
 int year = d.year();
 vector<int> daysInMonth = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
 vector<int> daysInMonthLeap = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

 int result = 0;
 if (leapyear(year))
 {
  for (int i = 0; i < month - 1; ++i)
   result += daysInMonthLeap[i];
  result += day;
 }
 else
 {
  for (int i = 0; i < month - 1; ++i)
   result += daysInMonth[i];
  result += day;
 }

 return result;
}

//finds out what number week of the year it is
int week_of_the_year(const Date& d)
{
 int daysSince1st = howManyDaysSince(d); //how many days have passed since jan 1st of given year?
 cout << "Days since 1st: " << daysSince1st << endl;
 int dow;     //day of week. sun = 0, mon = 1 etc..
 int dowJan1;     //day of week on jan 1st

 //find out day of week for current day
 Day day = findDayOfWeek(d);
 if (day == Day::sunday)
  dow = 0;
 else
  dow = static_cast<int>(day);

 //find out day of week for jan 1st of given year
 day = findDayOfWeek(Date(d.year(), Month::jan, 1));
 if (day == Day::sunday)
  dowJan1 = 0;
 else
  dowJan1 = static_cast<int>(day);

 //find week number
 int weekNum = ((daysSince1st + 6) / 7);
 if (dow < dowJan1)
  ++weekNum;
 return weekNum;
}

//compares dates
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);
}

//print to screen
ostream& operator<<(ostream& os, Date& d)
{
 return os << d.day() << ", " << static_cast<int>(d.month()) << ", " << d.year() << endl;
}

//write into Date
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 != ')')
 {
  //format error
  is.clear(ios_base::failbit);  //set the failbit
  return is;
 }

 dd = Date(y, Month(m), d);  //update dd
 return is;
}

//finds how many days have passed between two given dates
long int daysSince(const Date& date1, const Date& date2)
{
 long int daysSince = 0;
 Date tempDate = date1;

 //get how many years have passed between two dates
 int years = date2.year() - date1.year();

 //add number of days to daysSince for every year
 for (int i = years; i >= 1; --i)
 {
  //if leap year, add 366 days
  if (leapyear(tempDate.year()))
  {
   daysSince += 366;
  }
  //if not leap year only add 365
  else
   daysSince += 365;

  //increase tempDate so correct days are added
  tempDate.add_year(1);
 }

 //when we get to current year, calculate remaining days & add to total
 daysSince += howManyDaysSince(date2);

 return daysSince;
}

main.cpp
//main.cpp

#include "std_lib_facilities.h"
#include "dateclass.h"

int main()
{
 //intialise dates
 Date today(2018, Month::sep, 24);
 Date zero(1970, Month::jan, 1);

 //print how many days between 2 given dates, earliest date first
 cout << "Days since Jan 1st 1970: " << daysSince(zero, today) << endl;

 keep_window_open();

 return 0;
}


Ohhh kay. It's been a while. I didn't realise I had completely forgotten about this book over summer...whoops. Anyway, I'm going to try and do an exercise a night from now on. 

First things first, I realised that my implementation of leapyear() was completely wrong. I've now changed it and it's working properly now.

Now for the exercise, I didn't want to change the implementation of Date so instead I created a new function which takes two dates and works out how many days have passed since then. This new function is called daysSince(Date, Date). It takes two dates (no error checking just to keep code size down, so please put the earliest date first), then works out how many years are between the two. It then has a variable called daysSince which starts at 0. For every year either 365 or 366 (for leap years, checked using leapyear()) is added to it until we get to the current year. It then works out how many days since the start of the year using howManyDaysSince(Date) and adds that to the running total to get how many days between the two dates.

There are many sites on the internet which can work this out for you, however, they all seem to be out by a couple of days or even a month. I strongly believe my version is correct, if not, it is only out by one day. That I'm sure of.