Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методические указания.doc
Скачиваний:
9
Добавлен:
18.04.2015
Размер:
619.52 Кб
Скачать

Интерфейс

Интерфейс представляет собой частный случай абстрактного класса, все методы которого являются абстрактными, и который не имеет переменных класса. Синтаксис объявления интерфейсов различается в разных языках программирования. Так, в C++ вообще нет специального синтаксиса для интерфейсов и они объявляются подобно другим классам. А в Java, наоборот, существует специальное ключевое слово interface для объявления интерфейсов. При этом в Java и C# налагается ограничение, что у класса может быть только один предок, не являющийся интерфейсом, и произвольное количество предков-интерфейсов. Также в этих языках существует ограничение, что предками интерфейса могут быть только интерфейсы (предков может быть несколько). В C++ подобных ограничений нет. Приведем простой пример интерфейса на языке C++:

class Interchanger {

virtual int get ()=0;

virtual void put ()=0;

};

Исключения

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

  • Необходимость поддержания списка констант со всеми возможными кодами результата.

  • Необходимость при вызове каждого метода проверять возвращаемое им значение. При этом, программа превращается в наслоение множества вложенных if или switch-операторов, теряется ее читабельность.

Этот подход можно проиллюстрировать на таком примере:

if (methodA()<>ERROR) {

if (methodB()<>ERROR) {

…}

else {}

else {}

От перечисленных недостатков свободен второй механизм сообщения о критических ошибках – механизм исключений. Исключение представляет собой механизм обработки ошибочных ситуаций без использования кодов возврата из метода и включает в себя два аспекта: аспект описания обработки исключений и аспект генерации исключений.

Для описания обработки исключений программист определяет в рамках метода три типа блоков операторов: блок испытания, блок обработки исключений, финальный блок. Блок испытания объявляется с использованием ключевого слова try. Непосредственно за блоком испытаний следует один или несколько блоков обработки, объявляемых ключевым словом catch и, при необходимости, один финальный блок, объявляемый ключевым словом finally. Блок обработки может иметь одну переменную в качестве параметра. При генерации исключения обязательно указывается переменная, значение которой является параметром исключения. Генерация исключения осуществляется при помощи ключевого слова throw. Приведем пример описания обработки исключений на языке С++:

try {

methodA();

methodB();

}

catch (Error e) {…}

finally {…}

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

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

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

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

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

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

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

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

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

В момент начала выполнения вложенного блока испытания срабатывает встраиваемый код, отмечающий в стеке начало следующего фрейма исключения. В момент завершения выполнения – эта метка снимается. В результате образуется стек фреймов путем логического разделения стека переменных на части. Например, для следующего программного кода на языке C++:

try { -- Начало фрейма X

int x, y, z;

try { -- Начало фрейма Y

int a, b, c;

… -- Точка P

} catch (…) {…}

} catch (…) {…}

в точке P стек переменных и фреймов будет представлять собой следующее:

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