``````void Rational::reduce(Rational &f3){
int tnum, tden, temp, gcd;
tnum = labs(numerator);          								   	  // use non-negative copies
tden = labs(denominator);          						              //    (needs cmath)
if(tden==0 ){   											  		  // check for n/0
cout << "Illegal fraction: division by 0"; exit(1); }
else if( tnum==0 ){        									   	      // check for 0/n
numerator=0; denominator = 1; return; }
// this ‘while’ loop finds the gcd of tnum and tden
while(tnum != 0)
if(tnum < tden){												  // ensure numerator larger
temp=tnum; tnum=tden; tden=temp;							  // swap them
tnum = tnum - tden;}									      // subtract them
gcd = tden;															  // this is greatest common divisor
numerator = numerator / gcd;										  // divide both num and den by gcd
denominator = denominator / gcd;									  // to reduce frac to lowest terms
}	//ends function reduce

void Rational::normalize(Rational&){
if(denominator < 0){
numerator = numerator * -1;
denominator = denominator * -1;}
}	//ends function normalize

//sets the numerator and denominator to 0
void Rational::sglfrac() {

cout << "\nnumerator: "; cin >> numerator;
cout << "denominator: "; cin >> denominator;
}	//end function sglfrac

void Rational::add(Rational f1, Rational f2 ) {
//	a / b + c / d = [n](a * d + b * c) [d](b * d)
numerator = (f1.numerator * f2.denominator) + (f1.denominator * f2.numerator); //adds the numerator
denominator = (f1.denominator * f2.denominator);	//adds the denominator
}	//end function add``````

so far I've been trying to get the fraction to be reduced and normalized in the add function and I'm trying to use pass with reference but I am completely lost when it comes to passing by reference
so far all I've understood is passing by reference creates a copy of the item

Sorry I'm still getting this down so it's passing by value that makes the copy correct.

No, it's not passing by value, it's passing by reference. The reference is the memory address of the variable.

so if I run my reduce program it changes my numerator and denominator the same …

This is my class declaration

``````class Rational{
private:
int numerator;
int denominator;
float deci;
void reduce(Rational&);
void normalize(Rational&);

public:
Rational() : numerator(0), denominator(0)
{}
Rational(int num, int den) : numerator(num), denominator(den)			//constuctor
{}
void sglfrac();						//input a single fraction
void sub(Rational, Rational); …``````

It seems to me like you might have got a little confused about just what gets copied when you pass by value. If you have a function, like your `Rational::add()` function, and you declare it as:

``void add(Rational f2, Rational f3);``

Then you are using pass-by-value. I think that …

In many cases, it is preferable to pass classes by reference, even when you don't what to change them. In this case, you should use a `const` reference:

And just to clarify, the reason you'd do this is because when you pass by value, and thus create a copy of …

## All 13 Replies

so far all I've understood is passing by reference creates a copy of the item

Passing by reference does NOT create a copy of the item, that's the whole point of using it. It manipulates the original(by passing the memory address) so when your function ends any change you make to the variable doesn't go out of scope.

Sorry I'm still getting this down so it's passing by value that makes the copy correct.

so if I run my reduce program it changes my numerator and denominator the same for my normalized function.
So how would I get those changes to print in my add function?

Sorry I'm still getting this down so it's passing by value that makes the copy correct.

No, it's not passing by value, it's passing by reference. The reference is the memory address of the variable.

so if I run my reduce program it changes my numerator and denominator the same for my normalized function.
So how would I get those changes to print in my add function?

Because you're using a class, any variable declared for the class should be kept as long as an object derived from the class stays in scope. I'm not fully understanding the logic of your program. Your functions are taking another Rational object as a parameter but only add is actually doing anything with them. If you could post your class declaration that would help.

This is my class declaration

``````class Rational{
private:
int numerator;
int denominator;
float deci;
void reduce(Rational&);
void normalize(Rational&);

public:
Rational() : numerator(0), denominator(0)
{}
Rational(int num, int den) : numerator(num), denominator(den)			//constuctor
{}
void sglfrac();						//input a single fraction
void sub(Rational, Rational);		//subtract two fractions
void mult(Rational, Rational);		//multiply two fractions
void div(Rational, Rational);		//divide two fractions
void displaysgl();					//display a single fraction in n/d format
void displayfloat(Rational);		//display a single fraction in floating point format

};	//ends class Rational``````

This is my class declaration

``````class Rational{
private:
int numerator;
int denominator;
float deci;
void reduce(Rational&);
void normalize(Rational&);

public:
Rational() : numerator(0), denominator(0)
{}
Rational(int num, int den) : numerator(num), denominator(den)			//constuctor
{}
void sglfrac();						//input a single fraction
void sub(Rational, Rational);		//subtract two fractions
void mult(Rational, Rational);		//multiply two fractions
void div(Rational, Rational);		//divide two fractions
void displaysgl();					//display a single fraction in n/d format
void displayfloat(Rational);		//display a single fraction in floating point format

};	//ends class Rational``````

Thank you.

Your add, subtract, multiply, and divide functions are a little awkward. You're actually taking in THREE Rational objects (the two you've passed, and the one you called it from). Are you trying to add two and put the value into the Rational object which the function was called? That's what the "add" function you posted is doing. If so, then you're on the right track with that, however, you don't need to pass by reference.

Also, your reduce and normalize functions are private. This means that only the object which owns it can call those functions. None of your functions are calling normalize or reduce, so it's impossible to access them. You need to make those public, that way they can be accessed. You'll also need accessor functions to get the values of numerator and denominator in your other objects. Something as simple as:

``````int getNumerator(){return numerator;};
int getDenominator(){return denominator;};``````

will suffice.

You might as well post your whole code, so I can see exactly what you're trying to do and guide you better to achieve what you want.

Here is the full program

``````#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;

class Rational{
private:
int numerator;
int denominator;
float deci;
void reduce(Rational&);
void normalize(Rational&);

public:
Rational() : numerator(0), denominator(0)
{}
Rational(int num, int den) : numerator(num), denominator(den)			//constuctor
{}
void sglfrac();						//input a single fraction
void sub(Rational, Rational);		//subtract two fractions
void mult(Rational, Rational);		//multiply two fractions
void div(Rational, Rational);		//divide two fractions
void displaysgl();					//display a single fraction in n/d format
void displayfloat(Rational);		//display a single fraction in floating point format

};	//ends class Rational

//private member functions
void Rational::reduce(Rational &f3){
int tnum, tden, temp, gcd;
tnum = labs(numerator);          								   	  // use non-negative copies
tden = labs(denominator);          						              //    (needs cmath)
if(tden==0 ){   											  		  // check for n/0
cout << "Illegal fraction: division by 0"; exit(1); }
else if( tnum==0 ){        									   	      // check for 0/n
numerator=0; denominator = 1; return; }
// this ‘while’ loop finds the gcd of tnum and tden
while(tnum != 0)
if(tnum < tden){												  // ensure numerator larger
temp=tnum; tnum=tden; tden=temp;							  // swap them
tnum = tnum - tden;}									      // subtract them
gcd = tden;															  // this is greatest common divisor
numerator = numerator / gcd;										  // divide both num and den by gcd
denominator = denominator / gcd;									  // to reduce frac to lowest terms
}	//ends function reduce

void Rational::normalize(Rational&){
if(denominator < 0){
numerator = numerator * -1;
denominator = denominator * -1;}
}	//ends function normalize

//sets the numerator and denominator to 0
void Rational::sglfrac() {

cout << "\nnumerator: "; cin >> numerator;
cout << "denominator: "; cin >> denominator;
}	//end function sglfrac

void Rational::add(Rational f1, Rational f2 ) {
//	a / b + c / d = [n](a * d + b * c) [d](b * d)
numerator = (f1.numerator * f2.denominator) + (f1.denominator * f2.numerator); //adds the numerator
denominator = (f1.denominator * f2.denominator);	//adds the denominator
}	//end function add

void Rational::sub(Rational f1, Rational f2) {
//	a / b - c / d =[n]( a * d - b * c)[d](b * d)
numerator = (f1.numerator * f2.denominator) - (f1.denominator * f2.numerator); //subtracts the numerator
denominator = (f1.denominator * f2.denominator);							   //subtracts the denominator
}	//end function sub

void Rational::mult(Rational f1, Rational f2) {
//a / b * c / d = [n]( a * c) [d](b * d)
numerator = (f1.numerator * f2.numerator);									   //multiplys the numerator
denominator = (f1.denominator * f2.denominator);							   //multiplys the denominator
}	//end function mult

void Rational::div(Rational f1, Rational f2) {
//a / b / c / d =[n](a * d)[d](b * c)
numerator = (f1.numerator * f2.numerator);									   //divides the numerator
denominator = (f1.denominator * f2.denominator);							   //divides the denominator
}	//end function div

void Rational::displaysgl() {
cout << numerator << "/" << denominator;
}	//end function displaysgl

void Rational::displayfloat(Rational f3) {
deci = ((float)f3.numerator) / f3.denominator;
cout << fixed << setprecision( 3 )<< deci;
}	//end function displayfloat

int main() {
Rational f1;
Rational f2;
Rational f3;
Rational d;
int a;
do
{
cout << endl;
cout <<"1. Input rationals" << endl;
cout <<"2. Add rationals" << endl;
cout <<"3. Subtract rationals" << endl;
cout <<"4. Multiply rationals" << endl;
cout <<"5. Divide rationals" << endl;
cout <<"6. Quit" << endl << endl;
cout <<"Selection choice: ";
cin >> a;
switch(a)
{
case 1:
cout<<endl<<"Enter info for first Rational";
f1.sglfrac();
cout<<endl<<"Enter info for second Rational";
f2.sglfrac();
break;
case 2:
cout << setw(8);
f1.displaysgl();
cout << " + ";
f2.displaysgl();
cout << " = ";
f3.displaysgl();
cout << " or ";
d.displayfloat(f3);
cout << endl;
break;
case 3:
f3.sub(f1, f2);
cout << setw(8);
f1.displaysgl();
cout << " + ";
f2.displaysgl();
cout << " = ";
f3.displaysgl();
cout << " or ";
d.displayfloat(f3);
cout << endl;
case 4:
f3.mult(f1, f2);
cout << setw(8);
f1.displaysgl();
cout << " + ";
f2.displaysgl();
cout << " = ";
f3.displaysgl();
cout << " or ";
d.displayfloat(f3);
cout << endl;
break;
case 5:
f3.div(f1, f2);
cout << setw(8);
f1.displaysgl();
cout << " + ";
f2.displaysgl();
cout << " = ";
f3.displaysgl();
cout << " or ";
d.displayfloat(f3);
cout << endl;
break;
case 6:
exit(1);
break;
}
} while (a!=6);
}	//end main``````

What I'm trying to do is add sub mult divide 2 different fractions.

actually i was told to put the reduce and normalize in the private section
Thank you for the help so far

actually i was told to put the reduce and normalize in the private section
Thank you for the help so far

Ah, I see. So your add is adding the two Rational objects then you want it to call reduce and normalize. If that's the case, you shouldn't need to pass anything by reference. You should only need to call the functions inside your Add function, you shouldn't need parameters.

It seems to me like you might have got a little confused about just what gets copied when you pass by value. If you have a function, like your `Rational::add()` function, and you declare it as:

``void add(Rational f2, Rational f3);``

Then you are using pass-by-value. I think that you understand this, correct? But what is being copied exactly might be what you're not clear on. So if you have a statement in your code, like

``````Rational f1, f2, f3;

Then, when `add()` is called, copies of `f2` and `f3` are made within the `add()` function, for use there. Any changes that you make to `f2` and `f3` will not be passed back to the original variables in the calling function (probably `main()` . `f1` does not get copied at any point, changes that you make to the members of `f1` are retained after `add()` finishes.

When you pass by reference, then (as Red Goose already said) the memory addresses of the variables are passed to the function and no copies are made. So, your declarations might look like:

``void add(Rational &f2, Rational &f3);``

There is only ever one version of `f2` and `f3` (and also, as with the previous example, there is only ever one version of `f1` ).

In many cases, it is preferable to pass classes by reference, even when you don't what to change them. In this case, you should use a `const` reference:

``int myFunction(MyClass &arg1, const MyClass &arg2);``

the first argument is going to be changed by the function, but `arg2` definitely will not.

Some other points on your program:

• You don't have to pass a variable to a member function so, for example, your function `void normalize(Rational &);` could be declared as `void normalize();` (as Red Goose said).
• You have a member variable called `deci` , which I presume stores a decimal version of your number. This violates a principle of program design that you shouldn't repeat yourself. It would be betted to just have a function called `deci()` that calculates this value when it's needed. Otherwise, you have to worry about updating this value every time you perform an operation on the object.
• Your function `sglfrac` is trying to do too much. You should let the person that is using this class deal with details like this. What you should do as the class designed, is provide an access function that enables users to set these variables. So, using your current interface, you can set the values of numerator and denominator by doing:
``````Rational r;
r.sglfrac();``````

Seems convenient, right? Maybe, but what if I'm writing a program using your `Rational` class, and I happen to be Japanese? There's no way I can translate it. It's better to provide a function, called something like `set(int, int);` that you can use like this:

``````Rational r;
int num, denom;
cout << "\nnumerator: "; cin >> num;
cout << "denominator: "; cin >> denom;

r.set(num, denom);``````

This looks less neat, but it's actually much more flexible, and you won't have to keep re-writing your classes for use in different situations. You can sort of see the problem here:

``````cout<<endl<<"Enter info for first Rational";
f1.sglfrac();``````

you have half the user interface in the client code (your `main()` function in this case) and half in the class implementation! This sounds like "nit-picking" at the moment, but these are good habits to break early!

commented: Excellent points. +1
commented: Nice one. +6

In many cases, it is preferable to pass classes by reference, even when you don't what to change them. In this case, you should use a `const` reference:

And just to clarify, the reason you'd do this is because when you pass by value, and thus create a copy of your object, you also have to allocate the memory for an entirely new object. This isn't that bad with your small classes, but with larger ones, in larger codes, it can greatly hinder performance. The only thing the constant is doing is ensuring you don't accidentally change the value of the object you're passing. This makes tracking bugs easier since your compiler will give you an error if you accidentally try to change the constant. It's a favor to yourself to use it.

ok so I try calling them like this
reduce();
but I get this error
error C2660: 'Rational::reduce' : function does not take 0 arguments

sorry wrote that before i noticed the new posts

Remember, you also need to delete the reference parameter inside your class declaration.

Oh my i am actually understanding this and my program works :D yay thanks you guys. i know my code is super messy i'm a beginner and am just grasping the concepts so far thanks for the tips ravenous i do need to start to get my program to be more flexible and red goose your a life saver thank you even though i didn't need to use pass by reference i now know how to :) yay

commented: Good luck with your programming. +1
Be a part of the DaniWeb community

We're a friendly, industry-focused community of 1.19 million developers, IT pros, digital marketers, and technology enthusiasts learning and sharing knowledge.