Design Review

I started to learn C++ recently and as a starter was asked to design a class for fractions which can do *,+,- and / . This is the class that I designed. Are there any flaws in the design? Can anybody please help me?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
    #include <iostream>
#include <stdexcept>

using namespace std;

class Fraction
{
    int numerator;
    int denominator;

    public:

    Fraction() // Default constructor
    {
       numerator = 0;
       denominator = 1;
    }

    Fraction(int n,int d)  // parameterized constructor
    {
       numerator = n;
       if(d==0)
       {
           cout<<"Divide by zero error : Fraction Created as 0/1 \n";
           numerator = 0;
           denominator = 1;
       }
       else
           denominator = d;


     //Alternatively this can be used depending on if we want the program to be terminated in case of bad input
      /*try
      {
            if(d==0)
                throw std::overflow_error("Divide by zero exception");
            else
            {
                numerator = n;
                denominator = n;
            }
        }
        catch(std::overflow_error& e)
        {
            cout<<e.what();
        }*/




}

    Fraction(const Fraction& other) // copy constructor
    {
        numerator = other.numerator;
        denominator = other.denominator;
    }

    void reduce(Fraction& fract)   // Function for reducing the fraction
    {
        int gcd = gcdr(fract.numerator,fract.denominator);
        if(gcd!=1)
        {
            fract.numerator = fract.numerator/gcd;
            fract.denominator = fract.denominator/gcd;
        }
    }

    int gcdr ( int a, int b )      // Function for finding GCD of two numbers : Used for reducing
    {
      if ( a==0 )
          return b;
      return gcdr ( b%a, a );
    }

    int lcm(int a, int b)          // Function for finding LCM of two numbers : Used while addition and subtraction
    {
        int temp = gcdr(a, b);
        return temp ? (a / temp * b) : 0;
    }

    Fraction multiply(Fraction other) // Function for multiplying two fractions
    {
        Fraction result;
        result.numerator = numerator * other.numerator;
        result.denominator = denominator * other.denominator;
        reduce(result);
        return result;
    }

    Fraction inverse(Fraction other)   // Function for inversing a fraction : Used during division
    {
        Fraction result(other.denominator, other.numerator);
        return result;
    }

    Fraction divide(Fraction other)     // Function for dividing two fractions
    {
        Fraction result;
        result = multiply(inverse(other));
        return result;
    }

    Fraction add(Fraction other)         // Function for adding two fractions
    {
        Fraction result;
        int lcm_value = lcm(denominator,other.denominator);
        result.numerator =( numerator*lcm_value/denominator + other.numerator * lcm_value/other.denominator );
        result.denominator = lcm_value;
        reduce(result);
        return result;
    }

    Fraction subtract(Fraction other)   // Function for subtracting two fractions
    {
        Fraction result;
        int lcm_value = lcm(denominator,other.denominator);
        result.numerator =( numerator*lcm_value/denominator - other.numerator * lcm_value/other.denominator );
        result.denominator = lcm_value;
        reduce(result);
        return result;
    }

    bool is_equal(Fraction a)
    {
        int lcm_value = lcm(denominator,a.denominator);
        if ( (numerator*lcm_value/denominator) == (a.numerator * lcm_value/a.denominator))
            return true;
        else
            return false;
    }

    bool is_greater_than(Fraction a)
    {
        int lcm_value = lcm(denominator,a.denominator);
        if ( (numerator*lcm_value/denominator) > (a.numerator * lcm_value/a.denominator))
            return true;
        else
            return false;

    }

    void print_fraction()                 // Function for printing the fraction
    {
        cout<<numerator<<'/'<<denominator<<endl;
    }

    ~Fraction()
    {
        cout<<"Destroying objects\n";
    }
};
You're showing an implementation, not a design document. Working back to what the design might have been , I would ask why is the public interface so unusual for a value-semantic type: it is neither equality-comparable nor less-then-comparable, and therefore can't be used with standard C++ containers and algorithms. I would also recommend removing the copy ctor and dropping surprise output statements from ctor and dtor (at which time dtor can be removed too). Of course you're not showing the specs, so it's possible that this output is a requirement, but if it's just to implement the mathematical fraction type, take a look at std::complex for design ideas.
I think code wise its pretty well designed. To full advantage of the language though I would use operator+, operator-, operator*, operator/, operator<, operator>, operator==, and operator>> instead of the alternate Java function names add, subtract...etc.
Look up operator overloading. I think you'll like the feature but remember to employ those features in moderation. In this case I would think it would be appropriate though.
Topic archived. No new replies allowed.