Главная страница

ПК 2102. ПК(2102). П. Г. Колинько пользовательские контейнеры


Скачать 0.78 Mb.
НазваниеП. Г. Колинько пользовательские контейнеры
АнкорПК 2102
Дата28.11.2021
Размер0.78 Mb.
Формат файлаdocx
Имя файлаПК(2102).docx
ТипУчебно-методическое пособие
#284768
страница4 из 12
1   2   3   4   5   6   7   8   9   ...   12

1.3. Требования к отчету


В отчет по этой теме включите описание получившейся иерархии классов и пояснения:

1) какие классы пришлось добавить;

2) какие функции-члены пришлось переопределить и почему;

3) какие функции-члены сделаны недоступными и каким образом это осуществлено.

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

1.4. Контрольные вопросы


1. Какой базовый класс лучше всего использовать для производного класса «треугольник»?

2. То же — для класса «кружок».

3. То же — для класса «крестик».

4. Какой тип наследования следует выбрать: private, public или protected?

5. Можно ли вообще не указывать тип наследования?

6. В чем смысл объявления функций в базовом классе как виртуальных?

7. Нужно ли объявлять виртуальной функцию в производном классе, если в базовом она уже объявлена таковой?

8. Можно ли потребовать от компилятора проверить корректность объявления виртуальной функции в производном классе и как это сделать?

9. Можно ли запретить виртуальную функцию в классах-наследниках?

10. Что такое «чисто виртуальная функция»?

11. Обязательно ли переопределять все функции-члены базового класса в производном классе?

12. Зачем может понадобиться создание набора (массива или списка) указателей на разные типы объектов в пределах некоторой иерархии?

13. Как запретить для объекта вызов конструктора по умолчанию?

14. Как запретить вызов конструктора для использования в качестве неявного преобразователя типа?

15. Каким образом можно установить значение переменных объекта, объявленных с модификаторами const?

16. Каким образом следует инициализировать объект базового класса в конструкторе производного класса? Всегда ли это нужно делать?

17. Каким требованиям должны удовлетворять классы, чтобы между ними можно было сформировать отношение «является»?

18. Как установить между двумя классами отношение «содержит»?

19. Каким образом на экране появляются глаза и рот, если функция myshapedraw( ) не содержит кода для выдачи этих элементов фигуры?

20. Почему данные в классах line и rectangle сделаны protected?

2. ПОДДЕРЖКА ОБРАБОТКИ ИСКЛЮЧИТЕЛЬНЫХ СИТУАЦИЙ


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

Для задействования механизма особых ситуаций в программе нужно проделать следующее:

— обнаружив в программе место, где особая ситуация может возникнуть, надо придумать для нее уникальное название, например My_Error, и объявить соответствующий класс ошибок, возможно, пустой:

class My_Error {};

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

throw My_Error( );

Это утверждение создает объект класса My_Error. Если в объекте предусмотрены поля для данных, через них можно передать информацию обработчику ошибок: аргумент утверждения throw — это конструктор объекта;

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

try{ //Начало блока контроля.

Алгоритм, использующий функцию,
которая может создать особую ситуацию

(содержит утверждения throwMy_Error( ));

}

catch (My_Error)

{ Обработка особой ситуации }

Предложение catch размещается на том уровне вложенности функций, где обработка ситуации My_Error возможна. Если нужно обрабатывать несколько различных ошибок, после блока try последовательно размещаются соответствующие обработчики. При возникновении любой особой ситуации в блоке try его работа прерывается: происходит принудительный выход из всей цепочки вложенных функций, активных в точке особой ситуации, и вызов деструкторов для всех созданных при этом объектов, как это происходит при выходе из блока (области видимости). Этот процесс называется раскруткой стека: стек возвращается в состояние, в котором он был в момент входа в блок try.

Далее просматриваются блоки catch в том порядке, в каком они объявлены. Как только обнаруживается блок обработки ошибки нужного типа, управление передается ему. Остальные блоки catch не используются.

Если же выполнение блока try завершилось успешно, все блоки catch после него игнорируются.

Если для некоторого типа ошибки не обнаружено соответствующего блока catch, программа завершается аварийно. Чтобы этого избежать, последним в цепочке можно разместить блок catch(…), перехватывающий ошибки любого типа.

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

— устранение причины ошибки (уменьшение запроса на выделение памяти, отказ от обработки несуществующего или испорченного файла и т. п.);

— аварийное завершение программы (вызов abort( ));

— возбуждение особой ситуации другого типа (вызов throw с соответствующим аргументом);

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

Подробнее об особых ситуациях и их обработке см. [3, с. 222–230], [15, с. 232–256].

Правильный выбор уровня для размещения блока контроля позволяет сделать программу безопасной в смысле исключений (см. [12, с. 105–174]). Так, в учебном примере имеется следующая цепочка вызовов функций:

main( ) → screen_refresh( ) → myshape ∷ draw( ) → rectangle ∷ draw ( ) → put_line(a, b) → put_point(x, y) → on_screen(x, y).

Выход точки за пределы буферного массива SCREEN (экрана) выявляется функцией on_screen( ). Блок контроля вокруг вызова этой функции (или вызывающей ее put_point) не имеет смысла: на этом уровне ничего, кроме выдачи сообщения об ошибке, сделать нельзя, а такое сообщение можно выдать и не­по­средственно, не прибегая к механизму throwcath. На уровне main( ) или screen_refresh( ) обрабатывать ошибку поздно, здесь можно только прервать выполнение программы; без серьезной доработки класса shape содержательное сообщение об ошибке получить нельзя. В то же время блок контроля внутри функции myshapedraw( ) позволит локализовать ошибку при выводе прямоугольника — контура фигуры myshape и, возможно, попробовать изменить его размер. В общем случае проектирование реакции программной системы на ошибки должно выполняться одновременно с проектированием ее самой. Так, в программе, рассмотренной в учебном примере, можно снабдить каждую фигуру автоматически формируемым порядковым номером, значение которого можно выводить как часть сообщения об ошибке «выход за пределы экрана».

Если ошибка выявлена в конструкторе фигуры, фигура не создается. Это не является проблемой для цепочки базовых классов-значений. Исключение — класс shape, управляющий цепочкой фигур для рисования. Этот класс должен иметь деструктор, удаляющий сбойную фигуру из цепочки или заменяющий ее специальной фигурой — значком ошибки. Деструктор для класса shape должен быть виртуальным, чтобы правильно удалять объекты всех производных классов.

Классы ошибок могут образовывать иерархию. В этом случае можно перехватом ошибки базового класса перехватить и все производные от него. Рекомендуется использовать в качестве базы исключений стандартное исключение exception (потребуется директива #include <exception>). Это позволит подключить программу к системному механизму перехвата исключений. Кроме того, можно использовать имеющийся в классе механизм для сообщений. Конструктор класса exception имеет аргумент типа char* — строку (в стиле Си) для сообщения об ошибке. В блоке catch эта строка может быть получена вызовом виртуальной функции-члена what( ).

Например, класс ошибки перемещения фигуры может быть объявлен таким образом:

struct CantBeMoved : std::exception

{

CantBeMoved(const std::string& s) : std::exception(s.c_str( )) { }

};

Возбуждение исключения:

throw CantBeMoved("Line can't be moved: out of screen");

Перехват:

catch (CantBeMoved &ex) { std::cout << ex.what() << "\n\n"; }
1   2   3   4   5   6   7   8   9   ...   12


написать администратору сайта