#pragma once

#include <iostream>
#include <fstream>

// using namespace std; // poor practice - don't do - we'll discuss more later

//struct rational
//{
//
//};

class Rational // a class is like a blueprint for an object
{
public: // accessible/visible to all functions or objects outside of the class Rational
	
	// Recall the Rule of Three - if we explicitly define a copy constructor, then
	// we should define an overloaded assignment operator and destructor - vice versa

	// operations - member functions
	// constructors get called implicitly when an object is instantiated
	// Rational(); // default constructor - special member function
	Rational(int newNumerator = 0, int newDenominator = 1); // this is also a default constructor

	//Rational(int newNumerator, int newDeominator);
	// copy constructor - gets implicitly invoked when a Rational object is
	// copied either by pass-by-value calls or through object instantiation
	Rational(Rational &r);

	Rational& operator=(const Rational& rhs);

	// destructors get called implicilty when an object goes out of scope.
	// we use destructors to clean up resources, i.e. close file streams, free memory, etc.
	~Rational(); // destructor - special member function 

	// getters - accesors - return copies of the private data members
	int getNumerator() const; // constant functions
	int getDenominator() const;

	// setters - mutators - modifies the private data members w/ validated
	// arguments
	void setNumerator(int newNumerator);
	void setDenominator(int newDenominator);

private: // inaccessible/invisible to any functions or objects outside of the class Rational
	// attributes - data members
	int mNumerator,
		mDenominator;
}; 

// we'll make most overloaded operators non member functions (there are some
// exceptions including the overloaded assignment op (=))
Rational operator+ (Rational& lhs, Rational& rhs); // binary operators have two parameters
std::ostream& operator<< (std::ostream& lhs, const Rational& rhs);