Putting a Simple Program into Classes

• 04-29-2011
ian787
Putting a Simple Program into Classes
Hi All

I have a small problem that I'm wondering if anyone can help me with. I'm trying to put this program:

Code:

```#include <iostream> #include <cmath> using namespace std; int main() {         int a, b, c, d, numerator, denominator, minus_numerator, minus_denominator,times_numerator, times_denominator, divide_numerator, divide_denominator;         cout << "enter  first numerator";         cin >> a;         cout << "enter first denominator";         cin >> b;         cout << "enter second numerator";         cin >> c;         cout << "enter second denominator";         cin >> d;         numerator                        = (a*d) + (b*c);         denominator                        = b*d;         minus_numerator                = (a*d) - (b*c);         minus_denominator        = b*d;         times_numerator                = a*c;         times_denominator        = b*d;         divide_numerator        = a*d;         divide_denominator        = c*b;         cout << numerator << "/" << denominator << "\n" ;         cout << minus_numerator << "/" << minus_denominator << "\n";         cout << times_numerator << "/" << times_denominator << "\n";         cout << divide_numerator << "/" << divide_denominator << "\n";                 return 0; }```
Into classes But have not idea on how to do it. If anyone can hep that would be greatly appreciated! :)
• 04-29-2011
bernt
Ask yourself: "What sorts of objects am I working with?"
And by this I mean on a high level - don't answer with 'integers' :biggrin:. Luckily the idea seems fairly straightforward that you're working with fractions. So make a fractions class, define operations on it (addition, subtraction, multiplication, division, etc) and rewrite your main() to take advantage of that fractions class.

If the syntax for defining a class is getting you down get yourself over to google. "C++ Classses" "Overloading operators" (though overloading is not necessary here, it is a nice touch)
• 04-29-2011
nimitzhunter
something like
Code:

```class Frac { private:     int num;     int denom; public:   const Frac & operator+(something);     over load the rest of them. };```
• 04-29-2011
Babouche
Hello,

I'm not sure whether I'm qualified enough to give my insight on object-oriented programming (classes), but I'll try anyway.

When I cross that bridge and start using classes, off the top of my head, it happens in those situations:

1) I have a complex object that I want to burst into smaller, manageable pieces.
For example, to represent a car, I will create a class Car that encompasses a class Wheel (4 instances) and a class Engine.

2) I want to simplify I/O or interactions between related sets of data, while providing an interface to manipulate them.
A classic example is the class "string". You can add strings (as in concatenate them), and you have a great deal of methods that help computing something out of them, like finding out whether it contains a substring or getting the position of the first occurence of a character inside it.

While looking at your program, I have to admit, as of now I don't really see where using classes would prove useful.
You could encapsulate your algorithm in a function, so that you can repeatedly ask the user new parameters and output the result.

Or you could make a class out of it, and here's how I would proceed:

Code:

```class MyComputation { public:         MyComputation() {}         void readInputFromUser() {                 cout << "enter  first numerator";                 cin >> a;                 cout << "enter first denominator";                 cin >> b;                 cout << "enter second numerator";                 cin >> c;                 cout << "enter second denominator";                 cin >> d;         }         void printResults() {                 int numerator                        = (a*d) + (b*c);                 int denominator                        = b*d;                 int minus_numerator                = (a*d) - (b*c);                 int minus_denominator        = b*d;                 int times_numerator                = a*c;                 int times_denominator        = b*d;                 int divide_numerator        = a*d;                 int divide_denominator        = c*b;                 cout << numerator << "/" << denominator << "\n" ;                 cout << minus_numerator << "/" << minus_denominator << "\n";                 cout << times_numerator << "/" << times_denominator << "\n";                 cout << divide_numerator << "/" << divide_denominator << "\n";         }   private:         int a;         int b;         int c;         int d; };```
This way, you can ask for the input of a first computation, then a second, before printing the results of both.

With such a class, your program would look like:

Code:

```MyComputation myC; myC.readInputFromUser(); myC.printResults();```
• 04-29-2011
MK27
I made the mistake of trying this myself and got a little carried away. :D

Quote:

Originally Posted by Babouche
Or you could make a class out of it, and here's how I would proceed:

You could combine readInputFromUser() with the constructor, which would simplify things.

But IMO, while there is nothing wrong with this, it is just disguising a (fairly inflexible) procedural program as an OO one. As you write longer and more complex stuff, you will find it very helpful to keep the concept of "modularity" front and center in your mind. Aiming for modularity means doing things like breaking your task down into small functions, where each function does one thing in a flexible way. Part of the goal is to reduce repetition, for example:

Code:

```        cout << "enter  first numerator";         cin >> a;         cout << "enter first denominator";         cin >> b;         cout << "enter second numerator";         cin >> c;         cout << "enter second denominator";         cin >> d;```
Some obvious repetition. This could be:

Code:

```int getN (string &label) {         int rv;         cout << "enter " << label;         cin >> rv;         return rv; } string txt[4] = {"first numerator", "first denominator", "second denominator", "second denominator"}; int values[4]; for (int i = 0; i < 4; i++) value[i] = getN(txt[i]);```
This does not seem to be saving us anything in context, but it does make the program more dynamic because it is more modular, meaning it opens up an opportunity to use our function for other similiar purposes -- eg, if you had to get 100 numbers, it is easier.

OOP systemetizes modularity in a specific way, making your code easier to use, reuse, and understand. I'm not much for math and have never heard of a "minus denominator" before, and it is hard for me to see the point of what you are doing (meaning, I might have missed some angle), so I'll go with a class name like Babouche suggested. It seems to me that class computation has a few obvious members:

Code:

```        int numerator         int denominator         int minus_numerator         int minus_denominator         int times_numerator         int times_denominator         int divide_numerator         int divide_denominator```
These also look like pairs, so let's actually use arrays of two ints and consider the first one the numerator and the second one the denominator:

Code:

```class computation () {         private:                 int plain[2];                 int minus[2];                 int times[2];                 int divide[2]; }```
From the look of things, we do not actually need to store the numbers entered by the user in the class, we just have to use them to calculate these 8 numbers. Also, the input function from above does not need to be a method -- it could be from some other library or class (or you could put together with the class as a standalone static function). Anyway, the beginning of the constructor would then be:
Code:

```computation::computation () {         string txt[4] = {"first numerator", "first denominator", "second numerator", "second denominator"};         int v[4];         for (int i; i < 4; i++) v[i] = getN(txt[i]);```
Now we have the numbers we need, we just have to do the calculations. Let's use some internal methods:
Code:

```        private:                 void calcOne (int a, int b, int c, int d) {                         plain[0] = (a*d) + (b*c);                         plain[1] = b*d;                 }                 void calcTwo (int a, int b, int c, int d) {                         minus[0] = (a*d) - (b*c);                         minus[1] = b*d;                 }                 void calcThree (int *v, int a, int b, int c, int d) {                         *v = a*b;                         *(++v) = c*d;                 }```
Going back to the constructor, it might actually be better to abstract "class calculate" a bit by removing the IO and putting it back into main() -- as if this were a class used in the context of something bigger, where the interface might be different -- so what we now have is:

Code:

```calculate::calculate (int v[4]) {         calcOne(v[0], v[1], v[2], v[3]);         calcTwo(v[0], v[1], v[2], v[3]);         calcThree(&times[0], v[0], v[2], v[1], v[3]);         calcThree(&divide[0], v[0], v[3], v[2], v[1]); }```
Since we are removing IO from the class, we need some getters for the values -- or maybe just one:

Code:

```enum {         PLAIN,         MINUS,         TIMES,         DIVIDE }; void calculate::get (int which, int **p) {         switch (which) {                 case (PLAIN):                         *p = (int*)&plain;                         return;                 case (MINUS):                         *p = (int*)&minus;                         return;                 case (TIMES):                         *p = (int*)&times;                         return;                 case (DIVIDE):                         *p = (int*)&divide;                         return;         } }```
This is starting to look a little more complicated that the original program, but I think it does demonstrate some things about how to encapsulate and abstract -- ie, modularize -- in OOP. Putting it all together:

Code:

```#include <iostream> #include <string> enum {         PLAIN,         MINUS,         TIMES,         DIVIDE }; class calculate {         public:                 calculate (int v[4]) {                         calcOne(v[0], v[1], v[2], v[3]);                         calcTwo(v[0], v[1], v[2], v[3]);                         calcThree(&times[0], v[0], v[2], v[1], v[3]);                         calcThree(&divide[0], v[0], v[3], v[2], v[1]);                 }                 void get (int which, int **p) {                         switch (which) {                                 case (PLAIN):                                         *p = (int*)&plain;                                         return;                                 case (MINUS):                                         *p = (int*)&minus;                                         return;                                 case (TIMES):                                         *p = (int*)&times;                                         return;                                 case (DIVIDE):                                         *p = (int*)&divide;                                         return;                         }                 }         private:                 int plain[2];                 int minus[2];                 int times[2];                 int divide[2];                 void calcOne (int a, int b, int c, int d) {                         plain[0] = (a*d) + (b*c);                         plain[1] = b*d;                 }                 void calcTwo (int a, int b, int c, int d) {                         minus[0] = (a*d) - (b*c);                         minus[1] = b*d;                 }                 void calcThree (int *v, int a, int b, int c, int d) {                         *v = a*b;                         *(++v) = c*d;                 } }; using namespace std; int getN (string &label) {         int rv;         cout << "enter " << label << ": ";         cin >> rv;         return rv; } int main(void) {         int input[4];         string txt[4] = {"first numerator", "first denominator", "second denominator", "second denominator"};         for (int i = 0; i < 4; i++) input[i] = getN(txt[i]);         calculate eg(input);         int types[4] = {PLAIN, MINUS, TIMES, DIVIDE};         int *v;         for (int i = 0; i < 4; i++) {                 eg.get(types[i], &v);                 cout << v[0] << "/" << v[1] << endl;         }         return 0; }```
Tested this against the original code and the output is the same.
• 04-29-2011
ian787
Thanks guys for all you help!

You are all fantastic!! :D