I made the mistake of trying this myself and got a little carried away.
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(×[0], v[0], v[2], v[1], v[3]);
calcThree(÷[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*)−
return;
case (TIMES):
*p = (int*)×
return;
case (DIVIDE):
*p = (int*)÷
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(×[0], v[0], v[2], v[1], v[3]);
calcThree(÷[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*)−
return;
case (TIMES):
*p = (int*)×
return;
case (DIVIDE):
*p = (int*)÷
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.