8. Пространства имен. Обработка исключений. Оператор преобразования типа и explicit‑конструктор. (Семинары)
Описание файла
Файл "8. Пространства имен. Обработка исключений. Оператор преобразования типа и explicit‑конструктор." внутри архива находится в папке "Семинары". PDF-файл из архива "Семинары", который расположен в категории "". Всё это находится в предмете "информатика" из 2 семестр, которые можно найти в файловом архиве МГУ им. Ломоносова. Не смотря на прямую связь этого архива с МГУ им. Ломоносова, его также можно найти и в других разделах. .
Просмотр PDF-файла онлайн
Текст из PDF
Кафедра Компьютерных методов физики: программирование, первый курс, второй семестрЯзык программирования Си++Иванов А.П., Князева О.С.Семинар 8. Пространства имен. Обработка исключений.Оператор преобразования типа и explicit-конструктор.1. Пространства имен Си++При создании программ коллективами из нескольких программистов возникаетсвоеобразная проблема: разные программисты могут завести одно и то же имя (функции,класса, глобальной переменной, метки и т.п.) для своих собственных целей.
В такомслучае возникает конфликт имен: линковщик не может создать единую программу, таккак одно и то же имя используется по-разному в разных частях программы.Для преодоления конфликта имен в языке программирования Си++ введен механизмгруппирования имен в логически связанные группы имен или пространства имен.Пространство имен объявляется с помощью ключевого слова namespace следующимобразом:// ns_head.hnamespace my_names {void my_fun( double A[], int dim );class Ratio {public:int a,b;............};class other_class;............} // my_names namespace endПри этом в пространство имен достаточно включить только заголовок класса илифункции, тело класса и функции можно объявить позже, обычным порядком.Пространство имен является областью видимости, то есть, без явного указанияпространства имен объекты, определенные в этом пространстве имен просто не видны,соответствующие имена считаются неопределенными.
Однако в пределах пространстваимен все имена из него можно использовать без ограничений и указания дополнительныхпрефиксов.Напротив, чтобы воспользоваться объектом (функцией, классом и т.п.) за пределамиданного пространства имен нужно явно указать префикс пространства имен:#include <math.h>#include "ns_head.h"void main(){14.11.20111Кафедра Компьютерных методов физики: программирование, первый курс, второй семестр............double A[10];float y = my_names::my_fun(A,10);my_names::other_class obj;............}Здесь если пространства имен не использовать, то для функции sin() возникнетконфликт имен с функцией sin() из системной математической библиотеки.Если имена данного пространства имен в каком-то модуле используются часто, то можнообъявить его используемым «по умолчанию» в данном модуле (функции, блокепрограммного кода и т.п.):#include <math.h>#include "ns_head.h"using namespace my_names;void main(){............double A[10];float y = my_fun(A,10);other_class obj;............}Пространства имен – открыты, то есть, их можно пополнять новыми именами в любоймомент после их объявления (в том числе – в разных заголовочных файлах):namespace my_names {void my_fun( double A[], int dim );class other_class;}void main(){// здесь можно использовать только my_fun() и other_class.............}namespace my_names {double summa( double A[], int dim );class Ratio;}void f(){// здесь можно использовать и my_fun() и summa(), other_class и Ratio.............}Все имена из системной библиотеки языка Си (такие, как printf(), sin(),strlen()) помещены в стандартное пространство имен std, подключенноедирективной using по умолчанию в заголовочных файлах системных библиотек.14.11.20112Кафедра Компьютерных методов физики: программирование, первый курс, второй семестрПоэтому, если возникает конфликт имен с системной функцией, его можно разрешитьявно, полностью указывая префикс пространства имен:#include <math.h>namespace my_names {float sin( float x );}void main(){............float y = my_names::sin(3.14159/8); // вызывается собственная функцияdouble z = std::sin(3.14159/8); // вызывается системная функция............}Напомним, что потоки ввода-вывода языка Си++ тоже находятся в системномпространстве имен std, только, в отличие от функций системных библиотек языка Си,стандартное пространство имен для потоков Си++ не подключено автоматически, поэтомумы всегда употребляли директиву подключения этого пространства явно:#include <iostream>using namespace std;2.
Обработка исключенийПри работе программы часто возникают ситуации, которые нарушают нормальное еетечение: то пользователь ввел что-то неожиданное, то программист передал в функциюнеправильный параметр, то файла, который нужно открыть, нет на месте.Особенно сложные ситуации возникают, когда ошибка возникает в каком-либо«глубоком» вызове некоторой функции, а с тем, что делать с этой ошибкой можноопределиться только на несколько уровней выше по дереву вызовов функций.Обычная практика в таких случаях заключается в том, чтобы определить целочисленныекоды возврата функций, каждый из которых обозначает ту или иную ошибку. Функции,столкнувшиеся с ошибкой, возвращают эти коды наверх по иерархии вызовов до тех пор,когда на эти ошибки может быть организована какая-то разумная реакция.Но и тут остаются проблемы: конструкторы и деструкторы классов не могут возвращать никаких значений; целочисленного кода возврата зачастую мало для того, чтобы точно датьдиагностировать проблему: скажем, если не открылся какой-то файл, то помимофиксации факта «какой-то файл не открылся» хорошо бы явно сохранятьинформацию о его имени; такой код обработки ошибочных состояний может занимать до половины всегокода программы, программа делается чересчур громоздкой (т.к.
у каждого вызоваприходится проверять его код возврата).В языке программирования Си++ предусмотрен отдельный механизм для обработкиошибочных, или, точнее, исключительных (exceptions) состояний программы болеегибким и удобным образом.14.11.20113Кафедра Компьютерных методов физики: программирование, первый курс, второй семестрРассмотрим фрагмент программы, который преобразует целое число в символ собработкой ошибочных ситуаций, когда переданное число больше максимальновозможного кода символа:// Класс, в котором будут сохраняться детальная информация по// возникшему ошибочному состояниюstruct Range_error {int m_i;// поле, сохраняющее преобразуемое числоRange_error( int i ) { m_i = i; } // инициализирующий конструктор};struct Other_error {............ // класс для обработки какой-то другой ошибки};char to_char( int i ){char c = (char)i;if ( i != (int)c ) // проверка на точность преобразованияthrow Range_error(i); // возбуждение исключительного состояния// нормальное исполнение функции прерывается// управление передается иерархии вызвавших// функцийreturn c; // нормальный возврат, если ошибки не было}void f( int i ){try { // оператор «тестовой зоны»............char c = to_char(i); // проблемный вызов............}catch( Range_error x ) { // поймали исключительное состояние// печатаем диагностику:cerr << "Try to convert to char illegal number: " << x.m_i << endl;cerr << flush;}catch( Other_error ) {// обработка какого-то другого исключительного состояния, обратить// внимание: имя переменной после типа исключительного состояния// не указано, т.е.
подробной диагностики не будет!............throw; // данный оператор после частичной обработки возбуждает// то же самое исключительное состояние, которое было поймано –// для окончательной обработки на более высоком уровне// иерархии вызовов}catch(...) {// обработка любого непойманного ранее исключительного состоянияcerr << "Unknown exception" << endl << flush;exit(1); // завершение программы}............
// продолжение нормального исполнения функции f().}В этом примере вызывающая функция ограждает блок операторов, который можетвызвать исключительное состояние, блоком оператора try. Любое исключительноесостояние, которое возникнет в пределах операторов и вызовов функций этого блокаможет быть перехвачено обработчиком catch, аргументом которого указывается тип14.11.20114Кафедра Компьютерных методов физики: программирование, первый курс, второй семестрперехватываемого исключительного состояния, и, возможно, имя переменной, в которойбудут сохранены дополнительные параметры исключительного состояния для подробнойего диагностики.Принципиально важен порядок обработчиков catch, так как сработает первый жеподошедший по типу обработчик, прочие – не сработают. То есть, здесь аналогия сблоками else if() условного оператора.В конце (раньше – бессмысленно!) можно указать необязательный блок, который поймаетвообще любое возникшее исключение catch(…).С помощью механизма наследования исключительные состояния можно объединять вдревовидные иерархии:class math_err {public:double arg1, arg2;char op;math_err( double a1, char o, double a2 ) : arg1(a1), arg2(a2), op(o) {}};class overflow: public math_err{public:overflow( double a1, char o, double a2 ) : math_err(a1,o,a2) {}};class div_by_0: public math_err{public:div_by_0( double a1, double a2 ) : math_err(a1,'/',a2) {}};double divide({if ( fabs(b)double c = aif ( fabs(c)return c;}double a, double b)< 1.0E-10 ) throw div_by_0(a,b);/ b;> 1.0E+10 ) throw overflow(a,'/',b);void main(){............double x, y, z=0;restart:cin >> x >> y;try {z = divide(x,y);}catch (math_err q) {cerr << "illegal operation: " << x << ' / ' << y << ", repeate!";cerr << endl << flush;goto restart;}............}14.11.20115Кафедра Компьютерных методов физики: программирование, первый курс, второй семестр– так обрабатывать можно либо некоторую группу исключительных состояний целиком,либо, по желанию – отдельные исключительные состояния можно обработать отдельно,указывая блоки их обработки до общего блока группы:void main(){............double x, y, z=0;restart:cin >> x >> y;try {z = divide(x,y);}catch (div_by_0) {cerr << "divide by zero, result will be large!" << endl << flush;z = 1.0E+10;}catch (math_err q) {cerr << "illegal operation: " << x << ' / ' << y << ", repeate!";cerr << endl << flush;goto restart;}............}3.