Читать интересную книгу Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 75 76 77 78 79 80 81 82 83 ... 337
class="code">c; в противном случае необходимо считывать символы из потока cin, пока не встретится символ c. Теперь функцию clean_up_mess() можно написать следующим образом:

void clean_up_mess()

{

  ts.ignore(print);

}

Обработка ошибок всегда является сложной. Она требует постоянного экспериментирования и тестирования, поскольку крайне трудно представить заранее, какая ошибка может возникнуть в ходе выполнения программы. Защита программы от неправильного использования всегда представляет собой очень сложную задачу. Дилетанты об этом никогда не беспокоятся. Качественная обработка ошибок — один из признаков профессионализма.

7.8. Переменные

Поработав над стилем и обработкой ошибок, можем вернуться к попыткам улучшить функциональные возможности калькулятора. Мы получили вполне работоспособную программу; как же ее улучшить? Во-первых, необходимо ввести переменные. Использование переменных позволяет лучше выражать более длинные вычисления.

Аналогично для научных вычислений хотелось бы иметь встроенные имена, такие как pi и e, как в научных калькуляторах. Переменные и константы — основные новшества, которые мы внесем в калькулятор. Это коснется многих частей кода. Такие действия не следует предпринимать без весомых причин и без достаточного времени на работу. В данном случае мы вносим переменные и константы, поскольку это дает возможность еще раз проанализировать код и освоить новые методы программирования.

7.8.1. Переменные и определения

 Очевидно, что для работы с переменными и константами программа-калькулятор должна хранить пары (имя, значение) так, чтобы мы имели доступ к значению по имени. Класс Variable можно определить следующим образом:

class Variable {

public:

  string name;

  double value;

  Variable (string n, double v) :name(n), value(v) { }

};

Член класса name используется для идентификации объекта класса Variable, а член value — для хранения значения, соответствующего члену name. Конструктор добавлен просто для удобства.

Как хранить объекты класса Variable так, чтобы их значение можно было найти или изменить по строке name? Оглядываясь назад, видим, что на этот вопрос есть только один правильный ответ: в виде вектора объектов класса Variable.

vector<Variable> var_table;

В вектор var_table можно записать сколько угодно объектов класса Variable, а найти их можно, просматривая элементы вектора один за другим. Теперь можно написать функцию get_value(), которая ищет заданную строку name и возвращает соответствующее ей значение value.

double get_value(string s)

  // возвращает значение переменной с именем s

{

  for (int i = 0; i<var_table.size(); ++i)

  if (var_table[i].name == s) return var_table[i].value;

  error("get: неопределенная переменная", s);

}

Этот код действительно прост: он перебирает объекты класса Variable в векторе var_table (начиная с первого элемента и продолжая до последнего включительно) и проверяет, совпадает ли их член name c аргументом s. Если строки name и s совпадают, функция возвращает член value соответствующего объекта. Аналогично можно определить функцию set_value(), присваивающую новое значение члену value объекта класса Variable.

void set_value(string s, double d)

  // присваивает объекту класса Variable с именем s значение d

{

  for (int i = 0; i<var_table.size(); ++i)

  if (var_table[i].name == s) {

    var_table[i].value = d;

    return;

  }

  error("set: неопределенная переменная", s);

}

Теперь можем считать и записывать переменные, представленные в виде объектов класса Variable в векторе var_table. Как поместить новый объект класса Variable в вектор var_table? Как пользователь калькулятора должен сначала записать переменную, а затем присвоить ей значения? Можно сослаться на обозначения, принятые в языке С++.

double var = 7.2;

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

var = 7.2;

Что ж, возможно, но теперь мы не можем отличить определение новой переменной от синтаксической ошибки.

var1 = 7.2; // определение новой переменной с именем var1

var1 = 3.2; // определение новой переменной с именем var2

Ой! Очевидно, что мы имели в виду var2 = 3.2; но не сказали об этом явно (за исключением комментария). Это не катастрофа, но будем следовать традициям языков программирования, в частности языка С++, в которых объявления переменных с их инициализацией отличаются от присваивания. Мы можем использовать ключевое слово double, но для калькулятора нужно что-нибудь покороче, поэтому — следуя другой старой традиции — выбрали ключевое слово let.

let var = 7.2;

Грамматика принимает следующий вид:

Вычисление:

  Инструкция

  Печать

  Выход

  Инструкция вычисления

Инструкция:

  Объявление

  Выражение

Объявление:

  "let" Имя "=" Выражение

Вычисление — это новое правило вывода в грамматике. Оно выражает цикл (в функции calculate()), который позволяет выполнять несколько вычислений в ходе одного сеанса работы программы. При обработке выражений и объявлений это правило опирается на правило Инструкция. Например, инструкцию можно обработать следующим образом:

double statement()

{

  Token t = ts.get();

  switch (t.kind) {

  case let:

    return declaration();

    default:

    ts.putback(t);

    return expression();

  }

}

Вместо функции expression() в функции calculate() можем использовать функцию statement().

void calculate()

{

  while (cin)

  try {

    cout << prompt;

    Token t = ts.get();

    while (t.kind == print) t=ts.get(); // игнорируем "печать"

    if (t.kind == quit) return;         // выход

    ts.putback(t);

    cout << result << statement() << endl;

  }

  catch (exception& e) {

    cerr << e.what() << endl;           // выводим сообщение об ошибке

    clean_up_mess();

  }

}

Теперь необходимо написать функцию declaration(). Что следует сделать? Нужно убедиться, что после ключевого слова let следует Имя, а за ним — символ = и Выражение. Именно это утверждает грамматика. Что делать с

1 ... 75 76 77 78 79 80 81 82 83 ... 337
На этом сайте Вы можете читать книги онлайн бесплатно русская версия Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп.
Книги, аналогичгные Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

Оставить комментарий