Тверской государственный университет
Опубликован: 02.12.2009 | Доступ: свободный | Студентов: 2365 / 261 | Оценка: 4.47 / 4.24 | Длительность: 14:45:00
Лекция 2:

Классы

< Лекция 1 || Лекция 2: 123456 || Лекция 3 >

Класс RationalException

При проектировании класса необходимо предусмотреть возможность возникновения исключительных ситуаций при работе с объектами класса, не дающими возможность нормально продолжить работу. Когда такая ситуация возникает, класс должен выбросить исключение, указывающее на причину возникновения ситуации, и тогда клиент, вызвавший метод, приведший к возникновению ситуации, должен позаботиться о том, чтобы корректно ее обработать и по возможности продолжить работу.

Как правило, при проектировании класса параллельно с ним проектируется и класс, задающий исключительные ситуации. Такой класс должен быть объявлен как наследник класса Exception из библиотеки FCL, наследуя тем самым свойства и методы, общие для всех объектов, задающих исключения. Чаще всего, как это имеет быть место и в нашем случае, класс потомок устроен довольно просто и содержит набор конструкторов, вызывающих конструктор родительского класса, передавая ему информацию о возникшей ситуации. Более подробно поговорим об этом в соответствующей лекции, посвященной исключениям, а сейчас приведу код класса RationalException:

/// <summary>
/// Класс, задающий исключения при работе
/// с рациональными числами.
/// </summary>
public class RationalException : Exception
{
    public RationalException() { }
    public RationalException(string message) :
        base(message) { }
    public RationalException(string message,
        Exception e)
        : base(message, e) { }
}

Итоги. Как проектировать класс

Класс Rational является простым, но хорошим примером проектирования класса. Давайте перечислим основные вопросы, которые приходится решать при создании класса.

  • Тщательно спроектировать поля класса, сделав их закрытыми для клиентов. Для класса Rational эта проблема решается просто, поскольку свойств у рациональных чисел немного и они понятны.
  • Продумать стратегии доступа к закрытым полям класса, реализовав их в виде методов свойств. Для класса Rational естественной является стратегия "ни чтения, ни записи", поэтому такие методы отсутствуют у класса. Рациональное число рассматривается в операциях как неделимое целое, поэтому у клиентов не должно быть доступа к отдельным полям, представляющим части числа.
  • Тщательно спроектировать набор конструкторов класса. Класс Rational служит хорошим примером. Здесь есть конструктор без параметров, полный конструктор, закрытый конструктор и статический конструктор.
  • Задать при необходимости константы класса, используя для этого статический конструктор, как это сделано в классе Rational.
  • Тщательно спроектировать интерфейс класса - набор открытых методов, доступных клиентам класса и позволяющих выполнять различные операции над объектами класса. Для класса Rational набор таких методов определяется естественным образом. Это методы, выполняющие основные операции над числами - сложение, умножение и другие операции.
  • При необходимости добавить в класс перегрузку операций, что позволит клиентам класса строить выражения над объектами, используя привычные знаки операций и скобки.
  • Добавить в класс перегруженные операции отношения, позволяющие выполнять сравнение объектов на равенство и больше - меньше.
  • Переопределить методы, наследованные от родительского класса Object, в первую очередь переопределить метод ToString.
  • Параллельно с проектированием класса создать класс, описывающий исключительные ситуации, что позволит выбрасывать исключения в момент их возникновения, а клиентам класса позволит распознать и организовать обработку возникающих ситуаций.

Архитектура Решения

Как обычно, для демонстрации примеров данной лекции построено Решение с именем главы Ch3_1. В Решение включены три проекта. Проект DLL с именем ClassSamples содержит три класса - Person, Rational и SRational, служащих примерами описания классов и структур. Структура SRational этой DLL используется в проекте, построенном для примеров следующей лекции этого курса. Проект DLL с именем Geometrical_Figures содержит примеры классов, задающих геометрические фигуры и понятия, используемые в вычислительной геометрии. Эта DLL также будет использоваться в примерах, приводимых в последующих лекции курса. Консольный проект ConsoleWithClasses содержит традиционный класс Testing, большое число методов которого представляют собой различные тесты, иллюстрирующие работу с различными объектами классов из DLL, присоединенных к консольному проекту.

Задачи

  1. Создать DLL с классом Point, описывающим точку на плоскости, заданную декартовыми и полярными координатами. Среди методов класса Point предусмотреть метод Distance, вычисляющий расстояние до заданной точки. Построить Windows-проект, предоставляющий пользователю интерфейс для работы с классом Point.
  2. Создать DLL с классами Point и Line, описывающими точку и линию на плоскости. Построить Windows-проект, предоставляющий пользователю интерфейс для работы с DLL. Среди методов класса Line предусмотреть метод, определяющий принадлежность заданной точки линии.
  3. Создать DLL с классами Point и Square, описывающими точку и квадрат на плоскости со сторонами, параллельными осям координат. Построить Windows-проект, предоставляющий пользователю интерфейс для работы с DLL. Среди методов класса Square предусмотреть метод, определяющий принадлежность заданной точки квадрату.
  4. Создать DLL с классами Point и Circle, описывающими точку и круг на плоскости. Построить Windows-проект, предоставляющий пользователю интерфейс для работы с DLL. Среди методов класса Circle предусмотреть метод, определяющий принадлежность заданной точки кругу.
  5. Создать DLL с классами Point и Rectangle, описывающими точку и прямоугольник на плоскости со сторонами, параллельными осям координат. Построить Windows-проект, предоставляющий пользователю интерфейс для работы с DLL. Среди методов класса Rectangle предусмотреть метод, определяющий принадлежность заданной точки прямоугольнику.
  6. Создать DLL с классами Point и Rhomb, описывающими точку и ромб на плоскости с осями, параллельными осям координат. Построить Windows-проект, предоставляющий пользователю интерфейс для работы с DLL. Среди методов класса Rhomb предусмотреть метод, определяющий принадлежность заданной точки ромбу.
  7. Создать DLL с классами Point и Tetragon, описывающими точку и четырехугольник на плоскости. Построить Windows-проект, предоставляющий пользователю интерфейс для работы с DLL. Среди методов класса Tetragon предусмотреть метод, определяющий принадлежность заданной точки четырехугольнику.
  8. Создать DLL с классами Point и Triangle, описывающими точку и треугольник на плоскости. Построить Windows-проект, предоставляющий пользователю интерфейс для работы с DLL. Среди методов класса Triangle предусмотреть метод, определяющий принадлежность заданной точки треугольнику.
  9. Создать DLL с классами Account и Accounts, описывающими счет в банке и множество счетов клиентов, хранящихся в файле. Построить Windows-проект, предоставляющий пользователю интерфейс для работы с DLL.

Трансляция выражений

Пусть строка s задает некоторое выражение, значение которого требуется вычислить. Вот несколько примеров возможных выражений:

S1 = 2 +3*5/7;
S2 = 2 * sin(x) - (3 + cos(x)) * (x +5);
S3 = (x > y) && (x < 10) || (y > 5).

Рассмотрим классическую схему решения этой задачи. Первым делом производится разбор выражения - лексический анализ, где выражение преобразуется в последовательность лексем. Затем выражение записывается в виде обратной польской записи, а затем уже вычисляется значение преобразованного выражения.

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

Обратная польская запись выражения - это бесскобочная запись, где операции непосредственно предшествуют операнды операции. Наши выражения S1 - S3 в обратной польской записи имеют вид:

CS1 = 2 3 5 * 7 / +;
CS2 = 2 x sin * 3 x cos + x 5 + * -;
CS3 = x y > x 10 < && y 5 > ||;

Рассмотрим возможный алгоритм решения задачи. Пусть результатом лексического анализа выражения является стек лексем - stackExpression. Выходом алгоритма является очередь лексем - queueBackExpression, представляющая обратную польскую запись выражения. В качестве промежуточных данных используется очередь операций - queueOperations.

Пока stackExpression не пуст, читается очередная лексема Lex с вершины стека. Затем производится анализ типа этой лексемы и приоритета, если лексема задает операцию. Если лексема - операнд, то она помещается в очередь queueBackExpression. Если лексема - открывающая скобка, то она записывается в очередь queueOperations. Если лексема - закрывающая скобка, то из очереди queueOperations выгружаются все элементы вплоть до открывающей скобки. Эти элементы записываются в выходную очередь queueBackExpression. Знаки скобок в выходной стек не записываются. Если лексема - операция, то анализируется ее приоритет. Если приоритет лексемы выше приоритета последней операции, записанной в queueOperations, то новая операция записывается в очередь queueOperations. В противном случае операция из очереди выгружается и записывается в очередь queueBackExpression. Когда стек stackExpression опустоша ется, то все операции, оставшиеся в очереди queueOperations, выгружаются и записываются в очередь queueBackExpression.

Очередь queueBackExpression является входом для метода, вычисляющего значение выражения. Для вычисления выражения можно использовать стек stackResult. Алгоритм вычисления значения выражения можно описать следующим образом. Пока очередь queueBackExpression не пуста, читается очередная лексема. Если лексема - операнд, то она записывается в стек stackResult. Если лексема - операция, то из стека stackResult выгружаются предшествующие операции операнды, один или два в зависимости от того, является операция унарной или бинарной. Далее выполняется операция над операндами, и ее результат как операнд записывается в стек stackResult. Если все корректно, то по опустошению очереди на вершине стека stackResult будет операнд, представляющий значение выражения.

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

Задачи на трансляцию выражений

  1. Создать DLL с классом Lexeme, описывающим лексему. Построить Windows-проект, предоставляющий пользователю интерфейс для работы с DLL и позволяющий выполнить лексический анализ текста, задающего программу (фрагмент программы) на языке C#.
  2. (*) Создать DLL с классами Lexeme и AriphmeticExpression, описывающими лексему и арифметическое выражение. Выражение строится из чисел, функций, знаков операций и скобок и задается строкой текста. В классе предусмотреть метод, позволяющий вычислить значение выражения. Среди методов класса AriphmeticExpression предусмотреть метод разбора выражения, представляющий выражение в виде последовательности лексем. Построить Windows-проект, предоставляющий пользователю интерфейс для работы с DLL.
  3. (*) Создать DLL с классами Lexeme и AriphmeticExpression, описывающими лексему и арифметическое выражение с одной переменной x. Выражение строится из чисел, переменной x, функций, знаков операций и скобок и задается строкой текста. В классе предусмотреть метод, позволяющий вычислить значение выражения. Среди методов класса AriphmeticExpression предусмотреть метод разбора выражения, представляющий выражение в виде последовательности лексем. Построить Windows-проект, предоставляющий пользователю интерфейс для работы с DLL.
  4. (*) Создать DLL с классами Lexeme и AriphmeticExpression, описывающими лексему и арифметическое выражение с двумя переменными x и y. Выражение строится из чисел, переменных x и y, функций, знаков операций и скобок и задается строкой текста. В классе предусмотреть метод, позволяющий вычислить значение выражения. Среди методов класса AriphmeticExpression предусмотреть метод разбора выражения, представляющий выражение в виде последовательности лексем. Построить Windows-проект, предоставляющий пользователю интерфейс для работы с DLL.
  5. (**) Создать DLL с классами Lexeme и LogicExpression, описывающими лексему и логическое выражение. Выражение строится из констант true и false, отношений, функций, знаков операций и скобок и задается строкой текста. Отношение представляет собой пару арифметических выражений, связанных операцией отношения. В классе предусмотреть метод, позволяющий вычислить значение выражения. Среди методов класса LogicExpression предусмотреть метод, представляющий выражение в виде последовательности лексем. Построить Windows-проект, предоставляющий пользователю интерфейс для работы с DLL.
  6. (**) Создать DLL с классами Lexeme и LogicExpression, описывающими лексему и логическое выражение с одной переменной x. Выражение строится из констант true и false, отношений, функций, знаков операций и скобок и задается строкой текста. Отношение представляет собой пару арифметических выражений c переменной x, связанных операцией отношения. В классе предусмотреть метод, позволяющий вычислить значение выражения. Среди методов класса LogicExpression предусмотреть метод, представляющий выражение в виде последовательности лексем. Построить Windows-проект, предоставляющий пользователю интерфейс для работы с DLL.
  7. (**) Создать DLL с классами Lexeme и LogicExpression, описывающими лексему и логическое выражение c двумя переменными x и y. Выражение строится из констант true и false, отношений, функций, знаков операций и скобок и задается строкой текста. Отношение представляет собой пару арифметических выражений с переменными x и y, связанных операцией отношения. В классе предусмотреть метод, позволяющий вычислить значение выражения. Среди методов класса LogicExpression предусмотреть метод, представляющий выражение в виде последовательности лексем. Построить Windows-проект, предоставляющий пользователю интерфейс для работы с DLL.
  8. (**) Создать DLL с классами Lexeme, Expression и Assignment, описывающими лексему, выражение и оператор присваивания вида z = expression. Выражение в правой части оператора присваивания может быть одним из выражений, заданных в предыдущих задачах этого раздела. Построить Windows-проект, предоставляющий пользователю интерфейс для работы с DLL.
  9. Создать DLL с классами Student и Exam, описывающими студента и экзамен. Построить Windows-проект, предоставляющий пользователю интерфейс для работы с DLL.
  10. Создать DLL с сервисным классом Poisk, содержащего методы линейного и бинарного поиска. Построить Windows-проект, предоставляющий пользователю интерфейс для работы с DLL.
  11. Создать DLL с сервисным классом Sorting, содержащего методы сортировки. Построить Windows-проект, предоставляющий пользователю интерфейс для работы с DLL.
  12. Создать DLL с интерфейсным классом InputArray, позволяющий вводить одномерный массив с проверкой корректности ввода элементов. Построить Windows-проект, предоставляющий пользователю интерфейс для работы с DLL.

Проекты

  1. Дано множество точек P1, P2, \dots Pn со случайными координатами. Построить множество точек P1, P2, \dots Pm ( m <= n ), обход которых позволяет построить многоугольник без пересечений, если это возможно. Уметь вычислять площадь многоугольника, определять, является ли он выпуклым, принадлежит ли заданная точка внутренней области (границам) многоугольника. Построить реализацию в виде класса Polygon, включенного в состав DLL. Построить Windows-проект, предоставляющий пользователю интерфейс для работы с объектами класса Polygon.
  2. Построить Windows-проект, реализующий трансляцию выражений.
< Лекция 1 || Лекция 2: 123456 || Лекция 3 >
Илья Ардов
Илья Ардов

Добрый день!

Я записан на программу. Куда высылать договор и диплом?

Дарья Федотова
Дарья Федотова
Михаил Алексеев
Михаил Алексеев
Россия, Уфа, УГАТУ, 2002
Олег Корсак
Олег Корсак
Латвия, Рига