Обработка исключительных ситуаций
Исключительная ситуация (исключение) – это ошибка, возникающая во время выполнения программы. Например, ошибка работы с файлом, деление на ноль, обращение по несуществующему адресу памяти.
С++ позволяет программисту возможность реагировать на исключения и обрабатывать их. Механизм обработки исключений предназначен только для событий, которые происходят во время работы самой программы и указываются явным образом.
Функция, которая не может выполнить требуемое действие, генерирует исключение ( throw) .
Исключение обрабатывается где-то в контролируемом блоке ( try) , из которого вызывается эта функция. При этом отыскивается обработчик исключения (catch) и ему передается управление.
Если обработчик не найден, то вызывается функция terminate, аварийно завершающая программу.
Контролируемый блок – код, внутри которого может произойти исключение. При этом контролируются все вложенные вызовы функций.
try {
// операторы
}
catch( тип 1 имя 1)
{ // обработка исключения 1 }
…
catch( тип _n имя _n)
{ // обработка исключения n }
Обработчик начинается со слова catch, за которым следует в скобках тип исключения. Обработчики должны располагаться непосредственно после блока try. Если указать вместо параметра многоточие (…), то обработчик будет обрабатывать исключения любых типов.
После обработки исключения управление передается первому оператору, следующему за всеми обработчиками.
throw выражение ;
Тип выражения определяет тип исключения. Обычно используются специальные классы исключений.
throw без параметров используется внутри обработчика исключения для передачи исключения на более высокий уровень обработки.
При поиске обработчика исключений автоматически вызываются деструкторы локальных объектов.
= Max) throw StackError(); st[top++] = x; } Data pop() { if (top return st[--top]; } bool empty() { return ! top;} }; " width="640"
#include
template
class stack {
private:
Data st[Max];
int top;
public:
class StackError { };
stack (): top(0) {}
void push(Data x)
{ if (top = Max) throw StackError();
st[top++] = x; }
Data pop()
{ if (top
return st[--top]; }
bool empty() { return ! top;}
};
int main()
{ stack s1;
try
{ s1.push('a'); s1.push('b'); s1.push('c');
cout
cout
cout
}
catch (stack::StackError)
{ cout
}
cin.get();
return 0;
}
= Max) throw Full(); st[top++] = x; } Data pop() { if (top return st[--top]; } bool empty() { return ! top;} }; " width="640"
#include
template
class stack {
private:
Data st[Max]; int top;
public:
class Full { };
class Empty { };
stack (): top(0) {}
void push(Data x)
{ if (top = Max) throw Full();
st[top++] = x; }
Data pop()
{ if (top
return st[--top]; }
bool empty() { return ! top;}
};
int main()
{ stack s1;
try
{ s1.push('a'); s1.push('b');
// s1.push('c');
cout
cout
cout
}
catch (stack :: Full) { cout
catch (stack :: Empty){ cout
catch (...) { cout
cin.get();
return 0;
}
= Max) throw Error("Push","Full"); st[top++] = x; } Data pop() { if (top return st[--top]; } }; " width="640"
template
class stack {
private:
Data st[Max]; int top;
public:
class Error {
public:
char sender[20], err[20];
Error( char *s, char *t)
{ strcpy(sender,s); strcpy(err,t); }
};
void push(Data x)
- void push(Data x)
{ if (top = Max) throw Error("Push","Full");
st[top++] = x; }
Data pop()
{ if (top
return st[--top]; }
};
int main()
{ stack s1;
try
{ s1.push('a');
s1.push('b');
s1.push('c');
cout
cout
cout
}
catch (stack :: Error ex) { cout
cin.get();
return 0;
}
Стандартная библиотека C++ содержит несколько предопределенных классов исключений. Все они имеют общего предка exception.
Примеры : bad_alloc – ошибка при распределении памяти ;
invalid_argument – непр. аргумент ф-ции и т.д.
Многофайловые программы
Библиотека состоит из интерфейса (объявления функций и классов) и реализации (тел функций и методов).
Интерфейс представляет собой заголовочный файл с объявлениями с расширением .H.
Реализация – откомпилированный объектный ( OBJ) или библиотечный (LIB) файл .
Сборка многофайловых программ
Заголовочный файл с интерфейсом включается в любой исходный файл, использующий классы, при помощи #include.
Исходные и заголовочные файлы для компиляции включаются в файл проекта ( BPR, DEV, DSP). В этом файле хранится информация о дате файлов, что позволяет перекомпилировать только измененные файлы.
Межфайловые переменные
Переменная должна быть определена только в одном файле, в других – объявлена с помощью extern. Чтобы определить переменные с одинаковыми именами в разных файлах, используется static.
// файл A
int Var;
static int X;
// файл B
extern int Var;
static int X;
Var = 10;
Межфайловые функции и классы.
Функция определяется в одном файле, а объявляется во всех, которые ее используют. Чтобы определить функции с одинаковыми именами в разных файлах, используется static.
Классы должны быть определены во всех файлах, где используются.
Поэтому обычно классы определяются в заголовочных файлах и включаются во все файлы, где используются классы.
Определения методов должны быть в единственном экземпляре в любых файлах, использующих заголовочный файл.
Определения шаблонов функций и классов обязательно должны включаться в каждый файл, поэтому они размещаются в заголовочном файле.
//stack.h
class stack {
private:
char st[100];
int top;
public:
stack (): top(0) {}
void push (char x);
char pop();
bool empty();
};
// stack.cpp
#include “stack.h”
void stack::push(char x)
{st[top++] = x; }
char stack:: pop()
{ return st[--top]; }
Определение функции или переменной не должно включаться в файл дважды.
//headtwo.h
int Var;
//headone.h
#include “headtwo.h”
// app.cpp
#include “headone.h”
#include “headtwo.h”
Для предупреждения повторного включения используются директивы препроцессора.
#define имя // определение константы
#if выражение // условная компиляция
…
#elif выражение
…
#else
…
#endif
В выражениях можно проверить, определена ли константа с помощью defined( имя).
//stack.h
#if !defined (STACK)
#define STACK
class stack {
private:
char st[100];
int top;
public:
stack (): top(0) {}
void push (char x);
char pop();
bool empty();
};
#endif
namespace имя
{
…
}
Пример:
namespace math
{ const double pi = 3.1415926;
double len (double r)
{ return 2 * pi * r; }
}
Доступ осуществляется через область видимости
cout
либо с использованием описания using namespace имя
using namespace math;
cout
Директива using действует до конца блока.
Неоднократное определение пространства имен
Определения пространства имен могут встречаться в программе неоднократно.
namespace math
{ const double pi = 3.1415926;}
…
namespace math {
double len (double r)
{ return 2 * pi * r; }
}
В этом случае второе определение является продолжением первого. В стандартной библиотеке C++ большинство классов описаны в пространстве имен std.
Можно описать неименованное пространство имен. Оно получит имя, совпадающее с именем файла.

Обработка исключительных ситуаций в С++ (70 KB)

