// operator overloading and friends

#include <iostream>
#include <string>
#include <sstream>
using namespace std;

class rat {
public:
    rat() : num(0), den(1) {
        count++;
    }
    rat(const rat& r) : num(r.num), den(r.den) {
        count++;
    }
    rat(int n, int d) : num(n), den(d) {
        int f = gcd(num, den);
        num /= f;
        den /= f;
        count++;
    }

    // Here, const means that the object won't be modified
    string toString() const;
    void assign(int n, int d);
    static int getObjectCount();
    friend rat operator+(const rat& r1, const rat& r2);
    rat& operator+=(const rat& r);
    friend rat operator*(const rat& r1, const rat& r2);
    rat& operator=(const rat& r);
private:
    int num;
    int den;
    static int count;
    static int gcd(int a, int b);
};

rat operator+(const rat& r1, const rat& r2) {
    int n = r1.num * r2.den + r2.num * r1.den;
    int d = r1.den * r2.den;
    int f = rat::gcd(n, d);
    return rat(n / f, d / f);
}

rat& rat::operator=(const rat& r) {
    // always check for self-assignment
    if (this == &r) return *this;

    num = r.num;
    den = r.den;
    return *this;
}

rat& rat::operator+=(const rat& r) {
    *this = *this + r;
    return *this;
}

rat operator*(const rat& r1, const rat& r2) {
    int n = r1.num * r2.num;
    int d = r1.den * r2.den;
    int f = rat::gcd(n, d);
    return rat(n / f, d / f);
}

string rat::toString() const {
    ostringstream oss;
    oss << num << '/' << den;
    return oss.str();
}

void rat::assign(int n, int d) {
    num = n;
    den = d;
}

int rat::count = 0;

int rat::getObjectCount() {
    return count;
}

int rat::gcd(int a, int b) {
    if (a < 0) a = -a;
    if (b < 0) b = -b;

    if (a < b) {
        int temp = a;
        a = b;
        b = temp;
    }

    while (b != 0) {
        int temp = a;
        a = b;
        b = temp % b;
    }

    return a;
}

int main() {
    rat onehalf(1, 2);
    rat threefourths(6, 8);
    rat product(onehalf * threefourths);
    rat one(onehalf);
    one += onehalf;

    cout << onehalf.toString() << endl;
    cout << product.toString() << endl;
    cout << one.toString() << endl;
    cout << rat::getObjectCount() << endl;
}
