开发者

overloading >> for a fraction class C++

开发者 https://www.devze.com 2023-04-10 11:14 出处:网络
I\'m trying to overload the instream operator >> for a fraction class.I\'ve created a function that can take a string from the user and parse it into the proper arguments for my Fraction class but I\'

I'm trying to overload the instream operator >> for a fraction class. I've created a function that can take a string from the user and parse it into the proper arguments for my Fraction class but I'm unsure how to implement this in my >> overloading function.

There are three types of fractions that a user can input: 1. whole numbers (e.g. 5) 2. mixed numbers (e.g. 2+4/5) 3. regular fractions (e.g. 1/2)

My approa开发者_StackOverflow中文版ch was to accept this input as a string from the user in the main function, parse it to get the valid Fraction class parameters, then return this newly created fraction object to the stream. I'm just not sure how to do this.

In my operator overloading definition, I have this:

istream& operator>>(istream& in,const Fraction& input)

But if I'm accepting a string, shouldn't the type of the parameter here be a string? I'm just very confused about that part. I want to then return a Fraction object. Here's an example of handling whole numbers.

    int num1 = atoi(input.c_str());
    Fraction output(num1);
    in >> output;
    return in;

Am I on the right track here?


Your fraction is needed to be an output parameter so it can't be const:

istream& operator>>(istream& in, Fraction& input)

Then inside your function, you would extract into a std::string which you then parse, and store the relevant data into your input Fraction object.


Here's what I would do for demo code since everyone else already explained the problems.

class Fraction {
int top, bottom;
public:
    Fraction(int top_, int bottom_) :top(top_), bottom(bottom_) {}
    Fraction(const Fraction& rhs) : top(rhs.top), bottom(rhs.bottom) {}
    Fraction& operator=(const Fraction& rhs) {top=rhs.top; bottom=rhs.bottom; return *this}

    int get_numerator() {return top;}
    int get_denomerator() {return bottom;}
    double get_value() {return double(top)/bottom;}
};

istream& operator>>(istream& in, Fraction& input) {
    int numer;
    int denom=1;
    int whole=0;
    int peekchar;
    bool valid=false;

    in >> numer; //get the numerator
    peekchar = in.peek(); //peek at next character
    if(in && peekchar == '+') { //if next character is a +
        in.get(); //skip the + character
        whole = numer; //then first character was whole, not numerator
        in >> numer; //get the real numerator
        valid = true;
        peekchar = in.peek();
    }
    if(in && peekchar == '/') { //if next character is a /
        in.get(); //skip the / character
        in >> denom; //get the denominator
        valid = true;
    }
    if (in || valid) { //if we succeeded in reading
        if (denom == 0)
            denom = 1;
        numer += (whole*denom);
        input = Fraction(numer, denom);
     }
     return in;
}
ostream& operator<<(ostream& in,const Fraction& output) {
    return in << output.get_numerator() << '/' << output.get_denominator();
}
int main() {
    Fraction my_fract;
    cout << "Enter a fraction\n";
    cin >> my_fract;
    cout << "you entered " << my_fract;
}
}


You should be working with streams, not strings. If the user wants to input/output to/from a string it can always use an stringstream. Note that your definition is

istream& operator>>(istream& in,const Fraction& input)

which in stream language means extract a Fraction from a istream, so your input parameter shouldn't be const. On the other hand, to output a Fraction to an ostream one would declare

ostream& operator<<(ostream& in,const Fraction& input) //Here const is good

Also, one final note is that istream/ostream are specific implementations that work with char as element and the default traits. A more general implementation would work with any kind of stream, with operators defined like this

template< typename Elem, typename Traits >
std::basic_istream< Elem, Traits >& operator>>(std::basic_istream< Elem, Traits >& in, Fraction& input)

template< typename Elem, typename Traits >
std::basic_ostream< Elem, Traits >& operator<<(std::basic_ostream< Elem, Traits >& out, Fraction const& output)


For your operator>> function that you want to overload for the Fraction class, rather than taking an input std::string, parse it, and then attempt to make a new Fraction object from the parsed parameters, you should instead be doing all the parsing of the user's input inside the operator>> overloaded function, since that already has direct access to the input stream. In other words what you're doing is redundant, and a bit confusing ... with the operator>> overload for a Fraction object, the intention should be to take the entire user input and create a Fraction object from that user input ... not go through a couple steps before the Fraction object is complete.

So you would want something like:

//set values of Fraction object through pass-by-reference
istream& operator>>(istream& in,Fraction& input);

and use it like:

Fraction new_fraction_obj; //has only default-constructor-set values
std::cin >> new_fraction_obj;  //now will have the user-input values after call

Finally, if while attempting to parse the user input you find that it is not correctly formatted, or is the wrong types, etc., set the fail-bit of the istream object by calling ios::setstate() so that the user of the stream can detect there was something wrong with the input, and the Fraction object that is being passed-by-reference is in an invalid state.


The standard approach would be to break your custom input operation up into constituents:

std::istream & operator>>(std::istream & in, Fraction & input)  // not const!
{
  std::string token;

  if (!(in >> token)) { return in; }  // error

  int num, den;
  const bool res = parse_token(token, num, den);  // write this!

  if (!res)
  {
    in.setstate(std::ios::failbit);
    return in;
  }

  input.set(num, den); // or whatever
}

The crux is to write the parse_token(const std::string &, int &, int &) function that determines whether a string represents a valid fraction, and if yes puts the numerator and denominator in the two respective variables.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号