|
Программирование >> Поддержка объектно-ориентированного программирования
нельзя требовать, чтобы всегда был доступен исходной текст любой части большой программы, или чтобы у нас были права изменять любую часть большой программы, исходный текст которой мы имеем. На самом деле, пользователь не должен думать о внутреннем устройстве библиотек. Все эти проблемы перетрансляции и сопровождения могут привести к тому, что после создания первой версии библиотеки будет нельзя вводить в ней новые особые ситуации. Но такое решение не подходит практически для всех библиотек. Все эти доводы говорят за то, что особые ситуации нужно определять как иерархию классов (см. также $$9.6.1). Это, в свою очередь, означает, что особые ситуации могут быть членами нескольких групп: class network file err : public network err. public file system err { ошибки файловой система: в сети ошибки сети ошибки файловой системы Особую ситуацию network file err можно перехватить в функциях, обрабатывающих особые ситуации сети: void f() try { какие- то операторы catch (network err) { Ее также можно перехватить в функциях, обрабатывающих особые ситуации файловой системы: void g() try { какие-то другие операторы catch (file system err) { Это важный момент, поскольку такой системный сервис как работа в сети должен быть прозрачен, а это означает, что создатель функции g() может даже и не знать, что эта функция будет выполняться в сетевом режиме. Отметим, что в настоящее время нет стандартного множества особых ситуаций для стандартной математической библиотеки и библиотеки ввода-вывода. Задача комитетов ANSI и ISO по стандартизации С++ решить нужно ли такое множество и какие в нем следует использовать имена и классы. Поскольку можно сразу перехватить все особые ситуации (см. $$9.3.2), нет настоятельной необходимости создавать для этой цели общий, базовый для всех особых ситуаций, класс. Однако, если все особые ситуации являются производными от пустого класса Exception (особая ситуация), то в интерфейсах их использование становится более регулярным (см. $$9.6). Если вы используете общий базовый класс Exception, убедитесь, что в нем ничего нет кроме виртуального деструктора. В противном случае такой класс может вступить в противоречие с предполагаемым стандартом. 9.3.2 Производные особые ситуации Если для обработки особых ситуаций мы используем иерархию классов , то , естественно , каждый обработчик должен разбираться только с частью информации, передаваемой при особых ситуациях. Можно сказать, что, как правило, особая ситуация перехватывается обработчиком ее базового класса, а не обработчиком класса, соответствующего именно этой особой ситуации. Именование и перехват обработчиком особой ситуации семантически эквивалентно именованию и получению параметра в функции. Проще говоря, формальный параметр инициализируется значением фактического параметра. Это означает, что запущенная особая ситуация низводится до особой ситуации, ожидаемой обработчиком. Например: class Matherr { ... virtual void debug print(); class Int overflow : public Matherr { public: char* op; int opr1, opr2;; int overflow(const char* p, int a, int b) { cerr << op << ( << opr1 << , << opr2 << ); } void f() try { g(); catch (Matherr m) { При входе в обработчик Matherr особая ситуация m является объектом Matherr, даже если при обращении к g() была запущена Int overflow. Это означает, что дополнительная информация, передаваемая в Int overflow, недоступна. Как обычно, чтобы иметь доступ к дополнительной информации можно использовать указатели или ссылки. Поэтому можно было написать так: int add(int x, int y) сложить x и y с контролем if (x > 0 && y > 0 && x > MAXINT - y x < 0 && y < 0 && x < MININT + y) throw Int overflow( + , x, y); Сюда попадаем, либо когда проверка на переполнение дала отрицательный результат, либо когда x и y имеют разные знаки return x + y; void f() try { add(1,2); add(MAXINT,-2); add(MAXINT,2); catch (Matherr& m) { ... m.debug print(); а дальше переполнение Здесь последнее обращение к add приведет к запуску особой ситуации, который, в свою очередь, приведет к вызову Int overflow::debug print().Если бы особая ситуация передавалась по значению, а не catch (Matherr) { if (can handle it) { сделать ее else { throw; особой ситуации если обработка возможна. повторный запуск перехваченной Повторный запуск записывается как оператор throw без параметров. При этом снова запускается исходная особая ситуация, которая была перехвачена, а не та ее часть, на которую рассчитан обработчик Matherr. Иными словами, если была запущена Int overflow, вызывающая h() функция могла бы перехватить ее как Int overflow, несмотря на то, что она была перехвачена в h() как Matherr и запущена снова: void k() try { h(); ... catch (Int overflow) { ... Полезен вырожденный случай перезапуска. Как и для функций, эллипсис ... для обработчика означает любой параметр , поэтому оператор catch (... ) означает перехват любой особой ситуации: void m() try { какие- то операторы catch (...) { привести throw; все в порядок Этот пример надо понимать так: если при выполнении основной части m() возникает особая ситуация, выполняется обработчик, которые выполняет общие действия по устранению последствий особой ситуации, после этих действий особая ситуация, вызвавшая их, запускается повторно. Поскольку обработчик может перехватить производные особые ситуации нескольких типов, порядок, в котором идут обработчики в проверяемом блоке, существенен. Обработчики пытаются перехватить особую ситуацию в порядке их описания. Приведем пример: try { по ссылке, то была бы вызвана функция Matherr::debug print(). Нередко бывает так, что перехватив особую ситуацию, обработчик решает, что с этой ошибкой он ничего не сможет поделать. В таком случае самое естественное запустить особую ситуацию снова в надежде, что с ней сумеет разобраться другой обработчик: void h() try { какие-то операторы
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |