Thread: Putting a Simple Program into Classes

  1. #1
    Registered User
    Join Date
    Apr 2011
    Posts
    2

    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!

  2. #2
    Just a pushpin. bernt's Avatar
    Join Date
    May 2009
    Posts
    426
    Ask yourself: "What sorts of objects am I working with?"
    And by this I mean on a high level - don't answer with 'integers' . 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)
    Consider this post signed

  3. #3
    -bleh-
    Join Date
    Aug 2010
    Location
    somewhere in this universe
    Posts
    463
    something like
    Code:
    class Frac
    {
    private:
        int num;
        int denom;
    public:
       const Frac & operator+(something);
        over load the rest of them. 
    };
    "All that we see or seem
    Is but a dream within a dream." - Poe

  4. #4
    Registered User
    Join Date
    Apr 2011
    Posts
    5
    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();
    Last edited by Babouche; 04-29-2011 at 11:45 AM.

  5. #5
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    I made the mistake of trying this myself and got a little carried away.

    Quote Originally Posted by Babouche View Post
    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.
    Last edited by MK27; 04-29-2011 at 02:19 PM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  6. #6
    Registered User
    Join Date
    Apr 2011
    Posts
    2
    Thanks guys for all you help!

    You are all fantastic!!
    Last edited by ian787; 04-29-2011 at 02:35 PM. Reason: spelling mistake

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Simple Question about Classes
    By Loctan in forum C++ Programming
    Replies: 5
    Last Post: 06-26-2006, 02:40 AM
  2. Replies: 6
    Last Post: 06-30-2005, 08:03 AM
  3. Probably simple problem with classes
    By slaad in forum C++ Programming
    Replies: 6
    Last Post: 12-14-2004, 12:35 AM
  4. Fairly simple classes help please
    By sammacs in forum C++ Programming
    Replies: 13
    Last Post: 12-01-2004, 10:42 AM
  5. Simple yes/no question regarding classes
    By Ricochet in forum C++ Programming
    Replies: 5
    Last Post: 12-11-2003, 05:06 PM