# Thread: A Constructor from String to Fract

1. ## A Constructor from String to Fract

The code below is a book example that adds two fractions and prints out a message when the copy constructor is executed.

Code:
```#include <iostream>
#include <cstdlib>
using namespace std;

class Fraction {
private:
int num, den;      // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(Fraction const &src);

void set(int n, int d) {num = n; den = d; normalize();}
int get_num()  {return num;}
int get_den()  {return den;}
Fraction mult(Fraction other);
private:
void normalize();   // Put fraction into standard form.
int gcf(int a, int b);     // Greatest Common Factor.
int lcm(int a, int b);     // Lowest Common Denominator.
};

int main() {
Fraction f1(3, 4);
Fraction f2(f1);

cout << "The value of f3 is ";
cout << f3.get_num() << "/";
cout << f3.get_den() << endl;
system("PAUSE");
return 0;
}

// ---------------------------------------------------
// FRACTION CLASS FUNCTIONS

Fraction::Fraction(Fraction const &src) {
cout << "Now executing copy constructor." << endl;
num = src.num;
den = src.den;
}

// Normalize: put fraction into a standard form, unique
//  for each mathematically different value.
//
void Fraction::normalize(){

// Handle cases involving 0

if (den == 0 || num == 0) {
num = 0;
den = 1;
}

if (den < 0) {
num *= -1;
den *= -1;
}

// Factor out GCF from numerator and denominator.

int n = gcf(num, den);
num = num / n;
den = den / n;
}

// Greatest Common Factor
//
int Fraction::gcf(int a, int b) {
if (a % b == 0)
return abs(b);
else
return gcf(b, a % b);
}

// Lowest Common Multiple
//
int Fraction::lcm(int a, int b){
return (a / gcf(a, b)) * b;
}

Fraction fract;
int lcd = lcm(den, other.den);
int quot1 = lcd/den;
int quot2 = lcd/other.den;
fract.set(num * quot1 + other.num * quot2, lcd);
fract.normalize();
return fract;
}

Fraction Fraction::mult(Fraction other) {
Fraction fract;
fract.set(num * other.num, den * other.den);
fract.normalize();
return fract;
}```
The end of the chapter they show a way to initialize a Fraction object from a string.
Example:
Code:
```Fraction a = "1/2" , b = "1/3";

They suggest this string

Fraction arr_of_fract[4] = {"1/2" , "1/3" , "3/4"};

we need to declare within the fraction class declaration:
Fraction (char *s);```
Then the funtion
Code:
```Fraction::Fraction(char *s) {
int n = 0;
int d = 1;
char *p1 = strtok(s, "/, ");
char *p2 = strtok(NULL, "/, ");
if (p1 != NULL)
n = atoi(p1);
if (p2 != NULL)
d = atoi(p2);
set(n,d);
}```
Any ideas on how to implement this?

2. Originally Posted by tabl3six
The code below is a book example that adds two fractions and prints out a message when the copy constructor is executed.
Unless this is just an early example from which the author will build on, it is a bad example because:
• get_num and get_den should be declared const.
• add and mult should change the current object, or be declared as static member functions.
• Fraction objects were passed by value when they could have been passed by const reference.

Also, the user defined copy constructor is unnecessary, but perhaps the author wanted you to observe the output when the copy constructor is invoked.

Originally Posted by tabl3six
Any ideas on how to implement this?
It looks like the author already showed you an implementation. The bad part is that strtok changes the input string, which complicates the function's use. It would have been easier to just find the position of the '/' and thus separate the string into substrings.

3. Originally Posted by laserlight
It looks like the author already showed you an implementation. The bad part is that strtok changes the input string, which complicates the function's use. It would have been easier to just find the position of the '/' and thus separate the string into substrings.
Would stringstreams be a better approach ?

4. Originally Posted by manasij7479
Would stringstreams be a better approach ?
Maybe, except that there is no standard input manipulator to match constants like '/', so you would need to either resort to using a get() or replacing the '/' with a space, or something like that.

5. Originally Posted by laserlight
Maybe, except that there is no standard input manipulator to match constants like '/', so you would need to either resort to using a get() or replacing the '/' with a space, or something like that.
I don't understand....
Why not ignore that altogether?
__Like:
Code:
```istringstream is(input);
int n;
is>>n;
num= n;
is>>n;
is.clear();
is>>n;
den = n;```
...without any sort of error checking..but that would be easy to make..

6. Originally Posted by manasij7479
Why not ignore that altogether?
Write a program as a proof of concept using the code snippet you presented, test it, and you will understand why.

EDIT:
Actually, looking more carefully at your code snippet, you are not ignoring the '/'. You are just reading it in wrongly.

7. Actually, looking more carefully at your code snippet, you are not ignoring the '/'. You are just reading it in wrongly.
Yes..missed that.. :-]
Forgot that '/' was staying in the string stream after clearing the error state.

In that case;
Code:
```#include<iostream>
using namespace std;
int main()
{
string input;
cin>>input;
int num;
char dump;

istringstream in(input);

in>>num;
cout<<"Numerator "<<num<<endl;;

in>>dump;

in>>num;
cout<<"Denominator "<<num<<endl;

cin.get();
return 0;
}```

8. Originally Posted by manasij7479
Forgot that '/' was staying in the string stream.
Yep

Originally Posted by manasij7479
In that case;
Yes, you have to do something like that. If I had my way, you would be able to write:
Code:
`if (in >> num >> '/' >> den)`
or:
Code:
`if (in >> num >> literal('/') >> den)`
but alas, that is not so, unless you implement the literal input manipulator.

9. implement the literal input manipulator.
Would making a class and overloading the >> and << operators do that ?

10. I thought you could write a manipulator. You would make a functor that overloads the operator>> and operator<< in order to put/extract a character and test for success. Of course, instead of using a bool you have to return the stream so that kind of sucks. I don't think you can force the stream into a bad state when you need to without doing something very rude, so that is the only real problem I see.

11. Originally Posted by manasij7479
Would making a class and overloading the >> and << operators do that ?
Originally Posted by whiteflags
I thought you could write a manipulator. You would make a functor that overloads the operator>> and operator<< in order to put/extract a character and test for success. Of course, instead of using a bool you have to return the stream so that kind of sucks. I don't think you can force the stream into a bad state when you need to without doing something very rude, so that is the only real problem I see.
Refer to this post of mine: match_token. I actually have a more developed version that I placed in the Boost Vault, but the Boost Vault appears to have been removed.

12. I guess what I'm not understanding is where arr_of_fract[4] should go. I'm thinking it repaces objects f1, f2 in main(). Then how to call the function that converts the substrings to integers.

I guess I'll play around with the code, see if I can get it to work. I'm not understanding what's going on for the moment.

13. I'm sorry to be bringing this problem up again. Still can't get it to work. I've tried to simplify it so it prints out the converted strings, but the code compiles then crashes. I really don't know what I'm doing. ARRRRRRRRRRRRRRRRRRRRRRGGGGGGHHHHHHHHHH!!!!!!!!

Code:
```#include <cstdlib>
#include <iostream>
#include <cstring>
using namespace std;

class Fraction {
private:
int num, den;      // Numerator and denominator.
public:
Fraction(char *s);
void set(int n, int d) {num = n; den = d; normalize();}
int get_num()  {return num;}
int get_den()  {return den;}
private:
void normalize();   // Put fraction into standard form.
int gcf(int a, int b);   // Greatest Common Factor.
int lcm(int a, int b);   // Lowest Common Denominator.
};

int main() {

// HERE ARE THE NEW FRACT VARIABLES

Fraction s[3] = {"1/2", "1/3", "3/4"};

// PRINT THE RESULTING FRACTIONS
//not sure the follow is correct or even allowed

cout << s[1].get_num() << "/" << s[1].get_den() << endl;
cout << s[2].get_num() << "/" << s[2].get_den() << endl;
cout << s[3].get_num() << "/" << s[3].get_den() << endl;

system("PAUSE");
return 0;
}

// ---------------------------------------------------
// FRACTION CLASS FUNCTIONS

// Normalize: put fraction into a standard form, unique
//  for each mathematically different value.
//
void Fraction::normalize(){

// Handle cases involving 0

if (den == 0 || num == 0) {
num = 0;
den = 1;
}

if (den < 0) {
num *= -1;
den *= -1;
}

// Factor out GCF from numerator and denominator.

int n = gcf(num, den);
num = num / n;
den = den / n;
}

// Greatest Common Factor
//
int Fraction::gcf(int a, int b) {
if (a % b == 0)
return abs(b);
else
return gcf(b, a % b);
}

// Lowest Common Multiple
//
int Fraction::lcm(int a, int b){
return (a / gcf(a, b)) * b;
}

Fraction::Fraction(char *s){

int n = 0;
int d = 1;
char *p1 = strtok(s, "/, ");
char *p2 = strtok(NULL, "/, ");
if (p1 != NULL)
n = atoi(p1);
if (p2 != NULL)
d = atoi(p2);
set(n, d);
}```