книга (1119407), страница 14
Текст из файла (страница 14)
Абстрактные классы.Чистые виртуальные функцииЧистая виртуальная функция — функция вида:virtualТипвозвращаемогозначенияИмяфункции(Формальныепараметры)=0;Такая форма записи функции означает, что данная функция (точнее —метод класса) не имеет тела, описывающего ее алгоритм.Абстрактный класс — это класс, содержащий хотя бы одну чистуювиртуальную функцию.Нельзя создавать объекты на основе абстрактных классов, так как последние, имея в своем составе чистые виртуальные функции, не являютсяполноценными типами данных.
Однако указатели на абстрактные классысоздавать можно.Несмотря на то, что абстрактный класс не является полноценным типом, ТВМ для него создается. При этом в ТВМ перечисляются все виртуальные функции, в том числе и чистые виртуальные функции.В классе-наследнике чистая виртуальная функция может быть переопределена обычной виртуальной функцией с соответствующей заменой пустого значения на адрес данной функции в ТВМ класса-наследника.Класс-наследник абстрактного класса может также быть абстрактнымклассом, если в нем осталась (или была дополнительно введена) хотя бы одначистая виртуальная функция.88Средства обработки ошибок, исключения и обработка исключенийГлава 12.Средства обработкиошибок, исключенияи обработка исключенийАппарат обработки ошибок позволяет создавать надежно работающие программы, которые не завершаются аварийно в случае возникновения неожиданных аварийных ситуаций.
Такими аварийными ситуациями являются,например, отсутствие необходимого файла, блокировка записи информационной базы и т. д.Для обработки исключительных ситуаций используются ключевыеслова try, catch и throw.Часть программы, при выполнении которой необходимо обеспечитьобработку исключительных ситуаций, помещается в try-блок. В программеможет быть произвольное количество произвольно вложенных друг в другаtry-блоков.Если ошибка возникла внутри некоторого внутреннего try-блока (либов вызванной из него функции), то с помощью инструкции throw возбуждаетсяисключительная ситуация.
Сигнал о таком возбуждении будет перехвачени обработан в теле функции-обработчика, расположенном после ключевогослова catch. Обработчики помещаются сразу после try-блока. При возникновении исключительной ситуации управление передается в подходящийобработчик и в try-блок не возвращается (действительно, при возникновенииподобной ошибки продолжение исполнения части алгоритма, содержащейданную ошибку, нецелесообразно, а часто, и просто бессмысленно).Основные формы использования try, catch, throw:try {.
. .throw исключ_ситуация;. . .}catch(type){ /* . . . throw . . . */}. . .catch(type arg) { /* . . . throw . . . */}. . .catch(. . .){ /* . . . throw . . . */}Параметром инструкции throw является исключительная ситуация —объект некоторого типа, в частности, встроенного. Так, в качестве исключи89Средства обработки ошибок, исключения и обработка исключенийтельной ситуации может быть диагностическое сообщение (то есть, строка)или число.Если обработчик не может до конца обработать исключительную ситуацию, то инструкция throw без параметров передает обработку объемлющему try-блоку (так называемый перезапуск перехваченного исключения).12.1. Правила выбора обработчикаисключенияПри возникновении исключительной ситуации обработчики catch просматриваются в порядке их следования.
Срабатывает тот обработчик catch, типпараметра которого соответствует типу исключительной ситуациив инструкции throw.Обработчик с параметром базового типа перехватывает исключительную ситуацию типа-наследника. Поэтому обработчик с параметром типа-наследника должен быть объявлен раньше объявления обработчикас параметром базового типа.Аргумент arg при начале работы обработчика получает значение исключительной ситуации, указываемой в инструкции throw. Его можно использовать в теле обработчика. Обработчик catch(...) перехватывает всеисключительные ситуации. Поэтому он должен быть последним в спискеобработчиков.Если для исключительной ситуации не описан подходящий обработчикпосле соответствующего блока try, то данная ситуация перехватывается обработчиком для объемлющего try-блока.Если подходящий обработчик не найден во всех объемлющихtry-блоках, то выполняется стандартная функция terminate(), которая по завершении работы вызывает стандартную функцию abort(), аварийно завершающую работу программы.При описании функции можно указать типы исключительных ситуаций(спецификация исключений), которые может возбуждать функция:Если список после ключевого слова throw пуст, то функция не можетвозбуждать исключительных ситуаций с помощью инструкции throw (нипрямо, ни косвенно).90Средства обработки ошибок, исключения и обработка исключенийПример:void f1() throw ( int, over_flow );void noexcp ( int I ) throw();Если в прототипе функции отсутствует ключевое слово throw, тофункция может возбуждать любое исключение.При нарушении спецификации исключений, выполняется стандартнаяфункция unexpected(), аварийно завершающая программу.Блок try может содержать фрагмент программы, в котором объявляютсяобъекты.
При этом в конструкторах классов для данных объектов могутвозбуждаться исключительные ситуации в случае невозможности корректного создания объекта по передаваемым параметрам. в этом случаев подходящем обработчике для данного try-блока возможно корректно обработать ситуацию невозможности создания объекта.Пример:#include <iostream>using namespace std;class vect{int* p;int size;public:vect ( int n ): size (n){if (n < 1)throw n;p = new int [n];if ( p == 0 )throw "no free memory";};~vect (){delete[] p;}// . .
.};int g ( int m ){try{vect a(m);}catch (int n ){cout << "error of size " << n << '\n';return 1;}catch ( const char* er ){cout << er << '\n';return 2;};// . . .return 0;}91Средства обработки ошибок, исключения и обработка исключенийint main(){int ierr;int m;// . . .ierr = g (5);. . .ierr = g (0);// . . .ierr = g (m);// . . .return 0;}12.2. Стандартные исключенияСтандартные исключения — типы данных (классы или структуры), описывающие некоторые предопределенные исключительные ситуации,в частности, они могут составлять иерархию типов.Стандартные исключения могут быть включены в состав компиляторовC++ или поставляться вместе со стандартной библиотекой. Обычно, соответствующие классы и структуры содержатся в текстовых заголовочныхфайлах, например, в ‹exception›, ‹excpt.h› и других аналогичных, которыеподключаются явно или неявно директивой препроцессора #include.Стандартные исключения, описанные классом или структурой, содержат внутренние информационные члены, которые могут быть проанализированы, а также собственные конструкторы, деструкторы и необходимыеметоды.12.3.
Последовательность действийпри возникновенииисключительной ситуации1. Создание временного объекта — копии исключительной ситуации.2. Уничтожение объектов, созданных в try-блоке, с запуском для нихнеобходимых деструкторов, освобождающих динамическую память(свертка стека).3. Выход из try-блока.4. Подбор и выполнение обработчика для данного try-блокав соответствии с типом исключительной ситуации (статическаяловушка).5. Если необходимый обработчик для данного try-блока не найден илив обработчике имеется инструкция throw без параметров, сигнализирующая о незавершенности обработки исключительной ситуации,92Средства обработки ошибок, исключения и обработка исключенийто происходит выход в объемлющий try-блок с повторением пунктов 2–4 (динамическая ловушка).6.
Если исключительная ситуация осталась необработанной послевыхода из всех объемлющих try-блоков, то вызывается функцияterminate().93Множественное наследование, интерфейсыГлава 13.Множественноенаследование, интерфейсыМножественное наследование возникает, когда имеется несколько базовыхтипов и один тип — наследник.
При множественном наследовании появляется возможность моделирования более сложных отношений между типами.class X { . . . };class Y { . . . };class Z: public X, public Y { . . . };При описании производного класса каждый базовый класс имеет свойсобственный описатель типа наследования (явно указанный или неявнопредполагаемый).13.1.
Видимость примножественном наследованииПри множественном наследовании возникает проблема неоднозначностииз-за совпадающих имен в базовых классах.Пример:struct X{int i1;int jx;};struct Y{int i1;int jy;};struct Z: X, Y{int jz;};94Множественное наследование, интерфейсыint main(){Z z1;z1.i1 = 5;}// ошибка — неоднозначность: член i1// наследуется как из базового типа X, так// и из базового типа Y.return 0;Тем не менее, данная неоднозначность проявляется не при объявленииобъекта типа-наследника, а при использовании его членов, имеющихся в нескольких базовых типах.
Эту неоднозначность можно обойти при помощиоперации разрешения области видимости:z1.X::i1 = 5Таким образом, в тип-наследник попадают все члены базовых типов. Ноповторяющиеся имена необходимо сопровождать квалификатором базовоготипа.13.2. Виртуальные базовые классыПри многоуровневом множественном наследовании базовые классы могутбыть получены от общего предка. в этом случае итоговый производный классбудет содержать несколько подобъектов общего предка:class W{ . .
.};class X: public W{ . . . };class Y: public W{ . . . };class Z: public X, public Y{ . . . };Если необходимо, чтобы общий предок присутствовал в итоговомпроизводном классе в единственном экземпляре (например, если необходи95Множественное наследование, интерфейсымо, чтобы функции классов X и Y в классе Z использовали общие информационные члены класса W, или для экономии оперативной памяти), то наследование базовых классов от общего предка описывается с использованиемвиртуального наследования:class W{ . . .};class X: public virtual W{ . .