Материалы (12) (1115039), страница 2
Текст из файла (страница 2)
Если доступ ксамому исключению не нужен, то в операторе catch можно указывать только его тип.Существует специальный вид обработчика, перехватывающего любые исключения catch (…){---}. Естественно, он должен находиться в конце последовательности операторовcatch.Если для сгенерированного исключения в текущем try-блоке нет подходящегообработчика, оно перехватывается объемлющим try-блоком (main()f()g()h()).Если же подходящего обработчика так и не удалось найти, может произойтиненормальное завершение программы. При этом вызывается стандартная библиотечнаяфункция terminate (), которая в свою очередь вызывает функцию abort (), чего лучшеизбегать.Перехват исключений.void f (){try {throw E();}catch (H) {// когда мы сюда попадем?}}Обработчик будет вызван:(1) Если H того же типа, что и E.(2) Если H является однозначной открытой базой E.(3) Если Н и Е являются указателями, и (1) или (2) выполняется для типов, на которые ониуказывают.(4) Если H является ссылкой, и (1) или (2) выполняется для типа, на который H ссылается.Пример.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;}Результат работы программы на предыдущем слайде.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 ErrorПример использования классов исключений.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(); ...}Организованная таким образом обработка исключенийпозволяет легко модифицировать программы.Исключения, генерируемые в функциях.В заголовке функции можно указать типы исключений (через запятую), которые можетгенерировать функция (эту возможность удобно использовать при описании библиотечныхфункций):тип_рез имя_функции (список_арг) [const] throw (список_типов) { ...
}Если список типов пустой, то функция не может генерировать никаких исключений.Если же функция все-таки сгенерировала недекларированное исключение, вызываетсябиблиотечная функция unexpected () работающая аналогично функции terminate().Использование аппарата исключений – единственный безопасный способнейтрализовать ошибки в конструкторах и деструкторах, поскольку они не возвращаютникакого значения, и нет другой возможности отследить результат их работы.Если деструктор, вызванный во время свертки стека, попытается завершить свою работупри помощи исключения, то система вызовет функцию terminate(), что крайненежелательно. Отсюда важное требование к деструктору: ни одно из исключений, котороемогло бы появиться в процессе работы деструктора, не должно покинуть его пределы.Действия, выполняемые с момента генерацииисключения до завершения его обработки. При генерации исключения ( throw X ) создается временный объект – копия X(работает конструктор копирования).
С этой копией будет работать выбранныйдалее обработчик; она существует до тех пор, пока обработка исключения небудет завершена. Для всех других объектов try-блока, созданных к этому моменту, перед выходомиз try-блока освобождается память; при этом для объектов – экземпляров классоввызывается деструктор.
То же делается и для уже созданных подобъектов: членовкласса – объектов другого класса и баз. Этот процесс называют «раскруткой»(«сверткой») стека. Если в списке обработчиков catch этого try-блока найден подходящий, товыполняются его операторы; затем выполнение программы продолжается соператора, расположенного за последним обработчиком этого try-блока. Если в списке данного try-блока не нашлось подходящего обработчика, то поискпродолжается в динамически объемлющих try-блоках (при этом процесс сверткистека продолжается). Если подходящего обработчика так и не нашлось, то вызывается функцияterminate() и выполнение программы прекращается.Шаблоны1. Механизм шаблонов реализует в С++ параметрический полиморфизм.2.
Шаблон представляет собой предварительное описание функции или класса,конкретное представление которых зависит от параметров шаблона.3. Для описания шаблонов используется ключевое слово template, вслед закоторым указываются аргументы (параметры шаблона), заключенные в угловыескобки.4. Параметры шаблона перечисляются через запятую, и могут быть:а) объектами следующих типов:- целочисленного,- перечислимого,- указательного (в том числе указатели на члены класса),- ссылочного;б) именами типов (перед именем типа надо указыватьключевое слово class или typename).5. Параметры-объекты являются константами, их нельзя изменять внутришаблона.Шаблоны функций.template < список_параметров_шаблона >тип_рез-та имя_функции ( список_аргументов_функции ) { /*...*/ }Обращение к функции-шаблону:имя_функции < список_фактич._параметров_шаблона >(список_фактич_аргументов_функции );Пример: функция суммирования элементов массива.template < class T >T sum ( T array[ ], int size ) {T res = 0;for ( int i = 0; i < size; i++ ) res += array[ i ];return res;}Использование данного шаблона для массивов типа int [10] :int iarray [10];int i_sum;//...i_sum = sum < int > ( iarray, 10 );Можно задать аргумент size в виде параметра шаблона:template < class T, int size >T sum ( T array [ ] ) { /* ...
*/ }Тогда вызов sum будет таким:i_sum = sum < int, 10 > ( iarray );Неявное определение параметра-типа шаблонаПример 1.class complex{... public:complex ( double r = 0, double i = 0 );operator double ();......};template < class T >T f ( T& x, T& y ) {return x > y ? x : y;}double f ( double x, double y ){return x > y ? -x : -y;}int main ( ) {complex a ( 2 , 5 ), b ( 2 , 7 ), c;int i, j = 8, k = 10;}c = f ( a , b );// f < complex > (a , b)i = f ( j , k );return 0;// f < int > (j , k)Пример 2.template < class T >T max (T & x, T & y) {return x > y ? x : y;}int main ( ) {double x = 1.5, y = 2.8, z;int i = 5, j = 12, k;char * s1 = "abft";char * s2 = "abxde", * s3;z = max ( x, y );k = max < int > (i, j);// z = max (x, i);z = max < double > ( y, j );s3 = max (s2, s1);return 0;}// max <double>// max <int>// ошибка! - неоднозначный выбор параметров// max < char * >,// но происходит сравнение адресовtemplate <class T> T m1 (T a, T b) {cout << "m1_1\n";return a < b ? b : a;}template <class T, class B> T m1 (T a, T b, B c) {cout << "m1_2\n";c = 0; return a < b ? b : a;}template <class T, class Z> T m1 (T a, Z b) {cout << "m1_3\n";return a < b ? b : a;}int m1 (int a, int b) {cout << "m1_4\n";return a < b ? b : a;}int m1 (int a, double b) {cout << "m1_5\n";return a;}Пример 3.template <class T> T m1 (T a, T b) {cout << "m1_1\n";return a < b ? b : a;}template <class T, class B> T m1 (T a, T b, B c) {cout << "m1_2\n";c = 0; return a < b ? b : a;}template <class T, class Z> T m1 (T a, Z b) {cout << "m1_3\n";return a < b ? b : a;}int m1 (int a, int b) {cout << "m1_4\n";return a < b ? b : a;}int m1 (int a, double b) {cout << "m1_5\n";return a;}int main () {int i;m1 <int> (2, 3);// m1_1m1 <int, int> (2, 3);// m1_3m1 <int> (2, 3, i);// m1_2m1 (1, 1);// m1_4m1 (1.3, 1);// m1_3m1 (1.3, 1.3);// m1_1return 0;}Пример 3.// Если убрать первый шаблон:// m1_3// m1_3// m1_2// m1_4// m1_3// m1_3Алгоритм выбора оптимально отождествляемой функции сучетом шаблонов•Для каждого шаблона, подходящего по набору формальных параметров, осуществляетсяформирование специализации, соответствующей списку фактических параметров.•Если есть два шаблона функции и один из них более специализирован (т.е.
каждый егодопустимый набор фактических параметров также соответствует и второй специализации ),то далее рассматривается только он.•Осуществляется поиск оптимально отождествляемой функции из полученного наборафункций, включая определения обычных функций, подходящие по количеству параметров.При этом если параметры некоторого шаблона функции были определены путемвыведения по типам фактических параметров вызова функции, то при дальнейшем поискеоптимально отождествляемой функции к параметрам данной специализации шаблонанельзя применять никаких описанных выше преобразований, кроме преобразованийТочного отождествления.•Если обычная функция и специализация подходят одинаково хорошо, то выбираетсяобычная функция.•Если полученное множество подходящих вариантов состоит из одной функции, то вызовразрешим.