Like Tree1Likes

A Constructor from String to Fract

This is a discussion on A Constructor from String to Fract within the C++ Programming forums, part of the General Programming Boards category; The code below is a book example that adds two fractions and prints out a message when the copy constructor ...

  1. #1
    Registered User
    Join Date
    Jun 2011
    Posts
    46

    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 add(Fraction other);
        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);
    
        Fraction f3 = f1.add(f2);
    
        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;
        }
    
        // Put neg. sign in numerator only.
    
        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::add(Fraction other) {
        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. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    21,743
    Quote 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.

    Quote 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.
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User manasij7479's Avatar
    Join Date
    Feb 2011
    Location
    Kolkata@India
    Posts
    2,498
    Quote 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 ?
    Manasij Mukherjee | gcc-4.8.2 @Arch Linux
    Slow and Steady wins the race... if and only if :
    1.None of the other participants are fast and steady.
    2.The fast and unsteady suddenly falls asleep while running !



  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    21,743
    Quote 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.
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    Registered User manasij7479's Avatar
    Join Date
    Feb 2011
    Location
    Kolkata@India
    Posts
    2,498
    Quote Originally Posted by laserlight View Post
    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..
    Manasij Mukherjee | gcc-4.8.2 @Arch Linux
    Slow and Steady wins the race... if and only if :
    1.None of the other participants are fast and steady.
    2.The fast and unsteady suddenly falls asleep while running !



  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    21,743
    Quote 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.
    Last edited by laserlight; 08-15-2011 at 02:01 AM.
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    Registered User manasij7479's Avatar
    Join Date
    Feb 2011
    Location
    Kolkata@India
    Posts
    2,498
    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;
    }
    Last edited by manasij7479; 08-15-2011 at 02:09 AM.
    Manasij Mukherjee | gcc-4.8.2 @Arch Linux
    Slow and Steady wins the race... if and only if :
    1.None of the other participants are fast and steady.
    2.The fast and unsteady suddenly falls asleep while running !



  8. #8
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    21,743
    Quote Originally Posted by manasij7479
    Forgot that '/' was staying in the string stream.
    Yep

    Quote 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.
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  9. #9
    Registered User manasij7479's Avatar
    Join Date
    Feb 2011
    Location
    Kolkata@India
    Posts
    2,498
    implement the literal input manipulator.
    Would making a class and overloading the >> and << operators do that ?
    Manasij Mukherjee | gcc-4.8.2 @Arch Linux
    Slow and Steady wins the race... if and only if :
    1.None of the other participants are fast and steady.
    2.The fast and unsteady suddenly falls asleep while running !



  10. #10
    Registered User whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    7,706
    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. #11
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    21,743
    Quote Originally Posted by manasij7479
    Would making a class and overloading the >> and << operators do that ?
    Quote 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.
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  12. #12
    Registered User
    Join Date
    Jun 2011
    Posts
    46
    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. #13
    Registered User
    Join Date
    Jun 2011
    Posts
    46
    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;
        }
    
        // Put neg. sign in numerator only.
    
        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);
    }

  14. #14
    Registered User manasij7479's Avatar
    Join Date
    Feb 2011
    Location
    Kolkata@India
    Posts
    2,498
    Did you actually read the thread carefully?
    You do not seem to have done so.

    Also, this is an excellent time to learn using a debugger.
    Manasij Mukherjee | gcc-4.8.2 @Arch Linux
    Slow and Steady wins the race... if and only if :
    1.None of the other participants are fast and steady.
    2.The fast and unsteady suddenly falls asleep while running !



  15. #15
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,185
    In addition to what has been mentioned, here are some things that haven't:
    1. Arrays start at 0, not 1.
    2. You cannot modify a string literal; and therefore by extension you can't strtok a string literal either.

Page 1 of 2 12 LastLast
Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Passing a string to a constructor?
    By codeblue in forum C++ Programming
    Replies: 6
    Last Post: 04-27-2011, 05:40 AM
  2. Replies: 5
    Last Post: 02-21-2011, 01:19 AM
  3. Home-made string class constructor
    By aab19902 in forum C++ Programming
    Replies: 4
    Last Post: 03-11-2009, 04:15 AM
  4. DLL Global Object Constructor String Error
    By n00b3 in forum Windows Programming
    Replies: 1
    Last Post: 06-29-2008, 07:42 PM
  5. constructor to set variable to an empry string
    By wireless in forum C++ Programming
    Replies: 1
    Last Post: 03-29-2002, 10:29 AM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21