programming.systems.cpp.05.rtti (Лекции Волковой 2015)
Описание файла
Файл "programming.systems.cpp.05.rtti" внутри архива находится в папке "Лекции Волковой 2015". PDF-файл из архива "Лекции Волковой 2015", который расположен в категории "". Всё это находится в предмете "практикум (прикладное программное обеспечение и системы программирования)" из 4 семестр, которые можно найти в файловом архиве МГУ им. Ломоносова. Не смотря на прямую связь этого архива с МГУ им. Ломоносова, его также можно найти и в других разделах. .
Просмотр PDF-файла онлайн
Текст из PDF
Средства обработки ошибок. Исключения в С++Обработка исключительных ситуаций в С++ организуется с помощьюключевых словtry, catch и throw.Операторы программы, при выполнении которых необходимо обеспечитьобработку исключений, выделяются в try-catch - блок.Если ошибка произошла внутри try-блока (в частности, в вызываемых из tryблока функциях), то соответствующее исключение должно генерироваться спомощью оператора throw, а перехватываться и обрабатываться в теле одного изобработчиков catch, которые располагаются непосредственно за try-блоком.Исключение - объект некоторого типа, в частности, встроенного.Операторы, находящиеся после места генерации ошибки в try-блоке,игнорируются, а после обработки исключения управление передается первомуоператору, находящемуся за обработчиками исключений.
try-catch-блоки могутбыть вложенными.Общий синтаксис try-catch блока:try {….. throw исключение; …..}catch (type) {---/*throw;*/}catch (type arg) {---/*throw;*/}…catch (…) {---/*throw;*/}1Перехват исключений.С каждым try-блоком может быть связано несколько операторов catch. Онипросматриваются по очереди сверху вниз.Какой именно обработчик catch будет использоваться, зависит от типасгенерированного исключения.Выбирается первый обработчик с типом параметра, совпадающим с типомисключения. Ловушки с базовым типом (или с указателем или ссылкой набазовый тип) перехватывают все исключения с производным типом (или егоадресом), т.е. производные типы должны стоять раньше базовых типов.Если исключение перехвачено каким-либо обработчиком catch, аргумент argполучает его значение, которое затем можно использовать в теле обработчика.Если доступ к самому исключению не нужен, то в операторе catch можноуказывать только его тип.Существует специальный вид обработчика, перехватывающего любыеисключения - catch (…){---}.
Естественно, он должен находиться в концепоследовательности операторов catch.Если для сгенерированного исключения в текущем try-блоке нет подходящегообработчика, оно перехватывается объемлющим try-блоком (main()f()g()h()).Если же подходящего обработчика так и не удалось найти, может произойтиненормальное (аварийное) завершение программы. При этом вызываетсястандартная библиотечная функция terminate (), которая в свою очередьвызывает функцию abort (), чего лучше избегать.2Пример.class A {public:A () {cout << “Constructor of A\n”;}~A () {cout << “Destructor of A\n”;}};class Error {};class Error_of_A : public Error {};void f () {A a;throw 1;cout << “This message is never printed” << endl;}int main () {try {f ();throw Error_of_A();}catch (int) { cerr << “Catch of int\n”; }catch (Error_of_A) { cerr << “Catch of Error_of_A \n”; }catch (Error) { cerr << “Catch of Error\n”; }return 0;}3Результат работы программы на предыдущем слайде.Constructor of ADestructor of A // т.к.
в f обработчика нет, поиск идет дальше,// но при выходе из f вызывается деструктор// локальных объектов.Catch of intЕсли поменять строки внутри try, получим:Catch of Error_of_AЕсли закомментировать строку// catch (Error_of_A) { cerr << “Catch of Error_of_A \n”; },получимCatch of Error4Пример использования классов исключений.class MathEr{...virtual void ErrProcess();...};class Overflow : public Math Er{...
void ErrProcess();...};class ZeroDivide : public Math Er {... void ErrProcess();...};...Через параметры конструктора исключения можно передаватьлюбую нужную информацию.Если использовать виртуальные функции, можно после try-блоказадать единственный обработчик catch, имеющий параметр типабазового класса, но перехватывающий и обрабатывающий любыеисключения:try { ...}catch (MathEr & m) {... m. ErrProcess(); ...}Организованная таким образом обработка исключений позволяетлегко модифицировать программы.5Исключения, генерируемые в функциях.В заголовке функции можно указать типы исключений (через запятую), которыеможет генерировать функция (эту возможность удобно использовать при описаниибиблиотечных функций):тип_рез имя_функции (список_арг) [const] throw (список_типов) { ...
}Если список типов пустой, то функция не может генерировать никакихисключений.Если же функция все-таки сгенерировала недекларированное исключение,вызывается библиотечная функция unexpected () работающая аналогичнофункции terminate().Использование аппарата исключений – единственный безопасный способнейтрализовать ошибки в конструкторах и деструкторах, поскольку они невозвращают никакого значения, и нет другой возможности отследить результат ихработы.Если деструктор, вызванный во время свертки стека, попытается завершитьсвою работу при помощи исключения, то система вызовет функцию terminate(),что крайне нежелательно.
Отсюда важное требование к деструктору: ни одно изисключений, которое могло бы появиться в процессе работы деструктора, недолжно покинуть его пределы.6Действия, выполняемые с момента генерацииисключения до завершения его обработки. При генерации исключения ( throw X )создается объект-исключение– копия X (работает конструктор копирования). С этой копией будет работатьвыбранный далее обработчик; она существует до тех пор, пока обработкаисключения не будет завершена. Для всех других объектов try-блока, созданных к этому моменту, передвыходом из try-блока освобождается память; при этом для объектов –экземпляров классов вызывается деструктор.
То же делается и для ужесозданных подобъектов: членов класса – объектов другого класса и баз. Этотпроцесс называют «раскруткой» («сверткой») стека. Если в списке обработчиков catch этого try-блока найден подходящий, товыполняются его операторы; затем выполнение программы продолжается соператора, расположенного за последним обработчиком этого try-блока. Если в списке данного try-блока не нашлось подходящего обработчика, топоиск продолжается в динамически объемлющих try-блоках (при этом процесссвертки стека продолжается). Если подходящего обработчика так и не нашлось, то вызывается функцияterminate() и выполнение программы прекращается.7Механизм RTTI (Run-Time Type Identification).Механизм RTTI состоит из трех частей:1.операция dynamic_cast(в основном предназначена для получения указателя на объектпроизводного класса при наличии указателя на объектполиморфного базового класса);2.операция typeid(служит для идентификации точного типа объекта при наличииуказателя на полиморфный базовый класс);3.структура type_info( позволяет получить дополнительную информацию,ассоциированную с типом).Для использования RTTI в программу следует включить заголовок<typeinfo>.8(1).
Операция dynamic_cast реализует приведение типов(указателей или ссылок) полиморфных классов в динамическомрежиме.Синтаксис использования операции dynamic_cast :dynamic_cast< целевой тип >( выражение )Если даны два полиморфных класса B и D (причем D –производный от B), то dynamic_cast всегда может привести D* к B*.Также dynamic_cast может привести B* к D*, но только в томслучае, если объект, на который указывает указатель, действительноявляется объектом типа D (либо производным от него)!При неудачной попытке приведения типов результатом выполненияdynamic_cast является 0, если в операции использовалисьуказатели.Если же в операции использовались ссылки, генерируетсяисключение типа bad_cast.9Пример: пусть Base - полиморфный класс, а Derived - класс, производный от Base.Base * bp, b_ob;Derived * dp, d_ob;bp = & d_ob;dp = dynamic_cast <Derived *> (bp);if (dp)cout << «Приведение типов прошло успешно»;bp = &b_ob;dp = dynamic_cast <Derived *> (bp);if (!dp)cout << «Приведения типов не произошло»;10(2)-(3) Информацию о типе объекта можно получить с помощью операцииtypeid.Синтаксис использования операции typeid:typeid (выражение)typeid (имя_типа)илиОперация typeid возвращает ссылку на объект класса type_info,представляющий либо тип объекта, обозначенного заданным выражением, либонепосредственно заданный тип.В классе type_info определены следующие открытые члены:bool operator == (const type_info & объект); // для сравнения типовbool operator != (const type_info & объект); // для сравнения типовbool before (const type_info & объект);// для внутреннего использованияconst char * name ( );//возвращает указатель на имя типаОператор typeid наиболее полезен, если в качестве аргумента задатьуказатель полиморфного базового класса, т.к.
с его помощью во времявыполнения программы можно определить тип реального объекта, на который онуказывает. То же относится и к ссылкам.typeid часто применяется к разыменованным указателям ( typeid (* р) ). Еслиуказатель на полиморфный класс р == NULL, то будет сгенерировано исключениетипа bad_typeid.11Пример.class Base {virtual void f ( ) {...};};class Derived1: public Base { ...};class Derived2: public Base { ...};int main ( ) {int i;Base *p, b_ob;Derived1 ob1;Derived2 ob2;cout << «Тип i - » << typeid ( i ) .
name ( ) << endl;p = & b_ob;cout << “p указывает на объект типа ” << typeid ( * p ) . name ( ) << endl;p = & ob1;cout << “p указывает на объект типа ” << typeid ( * p ) . name ( ) << endl;p = & ob2;cout << “p указывает на объект типа ” << typed ( * p ) . name ( ) << endl;if ( typeid (ob1) == typeid (ob2) )cout << “Тип объектов ob1 и ob2 одинаков\n”;elsecout << “Тип объектов ob1 и ob2 не одинаков\n”;return 0;}12Стандартные исключения.Текст по генерации стандартных исключений вставляетсякомпилятором.Стандартные исключения объединены в иерархиюклассов, в вершине которой находится стандартныйабстрактный библиотечный класс exception, описанный в<stdexcept> :class exception {public:exception () throw ();exception (const exception &) throw ();exception & operator=(const exception &) throw ();virtual ~exception () throw ();virtual const char * what () const throw();...};13Иерархия классов стандартных исключений.exceptionlodic_errorbad_allocbad_castbad_exceptionbad_typeidios_base::failurelength_errordomain_errorout_of_rangeinvalid_argumentruntime_errorrange_erroroverflow_errorunderflow_errorИз этих классов исключений мы рассматриваем только исключенияbad_cast и bad_typeid, генерируемые соответственно при неверной работеопераций dynamic_cast и typeid, и расположенные в файле <typeinfo>,out_of_range, генерируемое методом at () контейнеров STL, и расположенное вфайле <stdexcept> ,bad_alloc, генерируемое операцией new при невозможности выделениядинамической памяти и расположенное в файле <new>.Чтобы операция new при ошибке выделения динамической памяти возвращала 0,надо использовать следующую ее форму:14Т * р = new (nothrow) T;Пример использования стандартных исключений.void f () {try { ...// использование стандартной библиотеки}catch (exception & e) {cout << “Стандартное исключение” << e.what() << ‘\n’;}catch (...) {cout << “Другое исключение” << ‘\n’;...}}Иерархию классов стандартной библиотеки можно брать за основудля своих исключений.15.