И.А. Волкова, А.В. Иванов, Л.Е. Карпов - Основы объектно-ориентированного программирования. Язык программирования С++ (1114893), страница 13
Текст из файла (страница 13)
Затем срабатываетконструктор класса С, создавая дополнительный вещественный массив.2) в конце работы удаляется созданный объект. Так как деструктор базовогокласса объявлен виртуальным, то сначала срабатывает деструктор текущегообъекта, удаляя вещественный массив, а затем — деструктор базового класса,удаляя целочисленный массив. В результате работы данной программы будетвыдана следующая информация:A()C()size int = 10~C() ~A()size double = 53) Если бы деструктор базового класса не был объявлен виртуальным, то приудалении объекта в соответствии с типом указателя pp1 для объекта был бывызван только деструктор базового класса.
в результате вещественный массивостался бы неудаленным, и была бы выдана информация:A()C()size int = 10~A()size double = 54) Несмотря на то, что метод sc() в классе C является виртуальным, он недоступен напрямую через указатель pp1, так как этого метода нет в структурекласса A. Поэтому для вызова этого метода для созданного объекта черезуказатель pp1 требуется преобразование:((C*)pp1)С другой стороны, если бы в классе с был описан метод с прототипом: int sa(),то он был бы виртуальным и по операции pp1−>sa() сработал бы его алгоритм,а не алгоритм метода sa(), объявленного в базовом классе.11.2. Реализация виртуальныхфункцийДля реализации механизма виртуальных функций используется специальный, связанный с полиморфным типом, массив указателей на виртуальныеметоды класса. Такой массив называется Таблицей Виртуальных Методов(ТВМ).
в каждый полиморфный объект компилятор неявно помещает указатель, условно обозначаемый какvtbl* pvtbl;на соответствующую ТВМ, хранящую адреса виртуальных методов.86Динамический полиморфизм, механизм виртуальных функцийДля указанного выше примера с виртуальными функциями будут созданы следующие структуры:В ТВМ типа-наследника имеющиеся адреса одинаковых методов замещаются, а новые — дописываются в конец.
Так, если бы в классе С былописан метод с прототипом int sa(), то ТВМ для класса С имела бы вид:A::& ~A()C::& sa()C::& ~C()C::& sc()Так как указатель на ТВМ находится в самом начале объекта, то ондоступен всегда, каким бы ни был тип указателя на объект.
Конечно, при этомиз ТВМ могут быть выбраны только те методы, которые имеются в структуреуказателя (входят в так называемый интерфейс), То есть, как показанов примере, если объект производного типа обрабатывается через указательбазового типа, то из ТВМ данного объекта можно вызывать только виртуальные методы, перечисленные в базовом типе. Естественно, при этом будетвыполняться алгоритм, определенный для данного объекта в соответствиис его типом.Издержками при использовании виртуальных функций является дополнительная память для неявного хранения указателя на ТВМ в каждомполиморфном объекте.87Динамический полиморфизм, механизм виртуальных функций11.3.
Абстрактные классы.Чистые виртуальные функцииЧистая виртуальная функция — функция вида: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.