Главная->Інформатика та програмування->Содержание->Отладка примера с английскими расстояниями

ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ В C++ (4-Е ИЗДАНИЕ) (часть 12) онлайн

Отладка примера с английскими расстояниями

Давайте взглянем на программу, в которой ввод пользователем данных в класс

Distance проверяется на наличие ошибок. Забудем на время про перевод расстоя-

ний из одних единиц в другие и про работу с ними. Пусть наша программа будет

просто получать от пользователя данные в футах и дюймах и выводить их на эк-

ран. Если же пользователь ошибается, нужно отклонить введенные данные, объ-

яснить ему, где он ошибся, и попросить ввести данные заново.

Программа очень проста, за исключением того, что метод getdist() расширен

и направлен на поддержку обработки ошибок. Частично эта программа исполь-

зует подход, показанный в приведенном выше коде. Кроме того, мы еще ввели

выражение, которое следит за тем, чтобы пользователь не вводил футы в формате

чисел с плавающей запятой. Это действительно важно, так как дюймы могут

иметь дробную часть, а футы — нет, и пользователь может слегка запутаться.

Обычно, ожидая ввод целочисленных значений, оператор извлечения просто

прерывает свою работу, увидев точку в десятичной дроби. При этом сообщение

об ошибке не выдается. Мы же хотим узнать о совершенной ошибке, поэтому

будем считывать значение числа футов не в виде int, а в виде строки. Затем мы

проверяем введенную строку при помощи созданной нами функции isFeet(),

возвращающей true, если число футов введено корректно. Для одобрения нашей

функцией введенное число должно содержать только цифры, и его значение

должно лежать в пределах от -999 до 999 (мы просто предполагаем, что более

далекие расстояния измерять не будем). Если с введенными футами все в по-

рядке, конвертируем строку в int с помощью стандартной библиотечной функ-

ции atoi(). Число дюймов вполне может быть дробным. Мы будем проверять

только их значения — они должны лежать в пределах от 0 до 12.0. Кроме того,

 

будем отслеживать наличие флагов ошибок ios. В общем случае будет установлен

failbit при вводе каких-либо символов вместо числа. Приведем листинг ENGLERR1.

Листинг 12.1. Программа ENGLERR

// englerr.cpp

// контроль ввода данных для класса английских расстояний

#include <iostream>

#include <string>

#include <cstdlib>      // для atoi(), atof()

using namespace std;

int isFeet(string);     //объявление

///////////////////////////////////////////////////////////

class Distance          // Класс английских расстояний

  {

  private:

    int feet;

    float inches;

  public:

    Distance()                 // конструктор (без аргументов)

      { feet = 0; inches = 0.0; }

    Distance(int ft, float in) // конструктор (2 арг.)

      { feet = ft; inches = in; }

    void showdist()            // вывод расстояния

      { cout << feet << "\'-" << inches << '\"';}

    void getdist();            // запросить длину

                               // у пользователя

  };

//---------------------------------------------------------

void Distance::getdist()    // получение длины от пользователя

  {

  string instr;             // для входной строки

 

  while(true)               // цикл, пока футы

                            // не будут правильными

    {

    cout << "\n\nВведите футы: ";

    cin.unsetf(ios::skipws);// не пропускать

                            // разделители

    cin >> instr;           // получить футы как строку

    if( isFeet(instr) )     // правильное значение?

      {        //да

      cin.ignore(10, '\n'); // съесть символы,

                            // включая разделитель строк

      feet = atoi( instr.c_str() ); // перевести

                                    // значение в целочисленное

      break;                // выход из цикла 'while'

      }                     // нет, не целое

    cin.ignore(10, '\n');   // съесть символы, включая

                            // разделитель строк

    cout << "Футы должны быть целыми < 1000\n";

    }  //конец цикла while для футов

 

  while(true)               // цикл проверки дюймов

    {

    cout << "Введите дюймы: ";

 

    cin.unsetf(ios::skipws);// не пропускать

                            // разделители

    cin >> inches;          // получить дюймы (тип float)

    if(inches>=12.0 || inches<0.0)

      {

      cout << "Дюймы должны быть между 0.0 и 11.99\n";

      cin.clear(ios::failbit); //"искусственно"

      }        // установить флаг ошибки

    if( cin.good() )        // все ли хорошо с cin

      {  //(обычно вводят не цифры)

      cin.ignore(10, '\n'); // съесть разделитель

      break;              // Ввод корректный, выйти из 'while'

      }

    cin.clear();          // ошибка; очистить статус ошибки

    cin.ignore(10, '\n'); // съесть символы с разделителем

    cout << "Неверно введены дюймы\n";  //заново

    }  //конец while для дюймов

  }

//---------------------------------------------------------

int isFeet(string str)      // true если введена строка

  {                         // с правильным значением футов

  int slen = str.size();    // получить длину

  if(slen==0 || slen > 5)   // не было или слишком много данных

    return 0;               // не целое

  for(int j=0; j<slen; j++) // проверить каждый символ

                            // если не цифра или минус

  if((str[j] < '0' || str[j] > '9')&&str[j] != '-')

      return 0;             // строка неправильных футов

  double n = atof( str.c_str() ); // перевод в double

  if( n<-999.0 || n>999.0 )  // вне допустимых значений?

    return 0;                // если да, неправильные футы

  return 1;                  // правильные футы

  }

///////////////////////////////////////////////////////////

int main()

{

  Distance d;             //создать объект Distance

  char ans;

  do

    {

    d.getdist();          // получить его значение

    cout << "\nРасстояние = ";

    d.showdist();         // вывести его

    cout << "\nЕще раз (y/n)? ";

    cin >> ans;

    cin.ignore(10,'\n' ); // съесть символы и

                          // разделитель

    } while(ans != 'n');  // цикл до 'n'

  return 0;

}

 

Мы использовали еще одну хитрость: установили флаг ошибки вручную.

Тем самым мы проверили, входят ли введенные дюймы в диапазон допустимых

значений. Если нет, мы устанавливает failbit с помощью

Мы использовали еще одну хитрость: установили флаг ошибки вручную.

Тем самым мы проверили, входят ли введенные дюймы в диапазон допустимых

значений. Если нет, мы устанавливает failbit с помощью

 

cin.clear(ios::failbit);//установить failbit

 

При проверке на наличие ошибок с помощью функции cin.good() флаг failbit

будет обнаружен и выведется сообщение об ошибке.

 

17