перегрузка >> для класса дроби C ++ - PullRequest
4 голосов
/ 05 октября 2011

Я пытаюсь перегрузить оператор instream >> для класса дроби. Я создал функцию, которая может взять строку у пользователя и проанализировать ее в подходящих аргументах для моего класса Fraction, но я не уверен, как реализовать это в моей >> функции перегрузки.

Существует три типа дробей, которые пользователь может ввести: 1. целые числа (например, 5) 2. смешанные числа (например, 2 + 4/5) 3. обычные дроби (например, 1/2)

Мой подход состоял в том, чтобы принять этот ввод как строку от пользователя в основной функции, проанализировать его, чтобы получить действительные параметры класса Fraction, а затем вернуть этот вновь созданный объект дроби в поток. Я просто не уверен, как это сделать.

В моем определении перегрузки оператора у меня есть это:

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

Но если я принимаю строку, не должен ли тип параметра здесь быть строкой? Я просто очень смущен этой частью. Я хочу затем вернуть объект Fraction. Вот пример обработки целых чисел.

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

Я на правильном пути?

Ответы [ 5 ]

5 голосов
/ 05 октября 2011

Ваша дробь должна быть выходным параметром, поэтому она не может быть const:

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

Тогда внутри вашей функции вы извлечете в std::stringкоторый вы затем анализируете и сохраняете соответствующие данные в вашем input Fraction объекте.

2 голосов
/ 05 октября 2011

Вот что я бы сделал для демонстрационного кода, поскольку все остальные уже объяснили проблемы.

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;
}
}
1 голос
/ 05 октября 2011

Для вашей функции operator>>, которую вы хотите перегрузить для класса Fraction, вместо того, чтобы принимать ввод std::string, проанализируйте его и затем попытайтесь создать новый объект Fraction из проанализированных параметров.вместо этого следует выполнять весь анализ ввода пользователя внутри перегруженной функции operator>>, поскольку она уже имеет прямой доступ к потоку ввода.Другими словами, то, что вы делаете, является избыточным и немного сбивает с толку ... с перегрузкой operator>> для объекта Fraction, намерение должно состоять в том, чтобы взять весь пользовательский ввод и создать объект Fraction из этогопользовательский ввод ... не проходите пару шагов, пока объект Fraction не будет завершен.

Так что вам нужно что-то вроде:

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

и использовать его как:

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

Наконец, если при попытке анализа пользовательского ввода вы обнаружите, что он неправильно отформатирован или имеет неправильный тип и т. Д., Установите бит сбоя объекта istream, вызвав ios::setstate()так что пользователь потока может обнаружить, что с вводом что-то не так, и объект Fraction, который передается по ссылке, находится в недопустимом состоянии.

1 голос
/ 05 октября 2011

Вы должны работать с streams, а не strings. Если пользователь хочет вводить / выводить в / из string, он всегда может использовать stringstream. Обратите внимание, что ваше определение

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

, что на языке потоков означает извлечение Fraction из istream, поэтому ваш входной параметр не должен быть постоянным. С другой стороны, для вывода Fraction в ostream нужно объявить

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

Также, последнее замечание: istream/ostream - это конкретные реализации, которые работают с char в качестве элемента и чертами по умолчанию. Более общая реализация будет работать с любым видом потока, с операторами, определенными как это

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)
0 голосов
/ 05 октября 2011

Стандартный подход будет разбивать вашу пользовательскую операцию ввода на составляющие:

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
}

Суть в том, чтобы написать функцию parse_token(const std::string &, int &, int &), которая определяет, представляет ли строка допустимую дробь, и, если да, помещает числитель и знаменатель в две соответствующие переменные.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...