
- •«Объектно-ориентированный анализ и проектирование»
- •1. Принципы ооп. Классы.
- •Описание классов.
- •Объекты класса.
- •Конструкторы
- •Конструктор копирования
- •Статические элементы класса
- •Дружественные функции и классы
- •Деструкторы
- •Перегрузка операций
- •Перегрузка унарных операций
- •Перегрузка бинарных операций
- •Перегрузка операции присваивания
- •Рекомендации по составу классов
- •2. Наследование
- •Ключи доступа
- •Простое наследование
- •Пример замещения функций (практикум)
- •Виртуальные методы
- •Множественное наследование
- •3. Отношения между классами. Диаграммы класссов на языке uml.
- •4. Шаблоны классов.
- •4.1. Определения шаблонов классов Queue и QueueItem
- •4.2. Конкретизация шаблона класса
- •4.3. Аргументы шаблона для параметров-констант
- •4.4. Функции-члены шаблонов классов
- •5. Обработка исключительных ситуаций
- •5.1. Общий механизм обработки исключений.
- •5.2 . Синтаксис исключений
- •5.3. Перехват исключений
- •5.4. Исключения в конструкторах и деструкторах
- •Vector(int n) // Конструктор
- •5.5. Список исключений функции.
- •6. Строки
- •Преобразование строк
- •7. Контейнерные классы
- •7.1. Векторы.
- •7.2. Двухсторонние очереди (deque).
- •7.3. Списки (List).
- •7.4. Стеки
- •7.5. Очереди (queue)
- •7.6. Очередь с приоритетами(priority_queue)
- •8. Ассоциативные контейнеры
- •8.1. Словари (map)
- •8.2. Словари с дубликатами (multimap)
- •8.3. Множества (set)
- •8.4. Множества с дубликатами (multiset)
- •8.5. Битовые множества (bitset)
5.3. Перехват исключений
Когда с помощью throw генерируется исключение, функции исполнительной библиотеки C++ выполняют следующие действия:
1) создают копию параметра throw в виде статического объекта, который существует до тех пор, пока исключение не будет обработано;
2) в поисках подходящего обработчика раскручивают стек, вызывая деструкторы локальных объектов, выходящих из области действия;
3) передают объект и управление обработчику, имеющему параметр, совместимый по типу с этим объектом.
При раскручивании стека все обработчики на каждом уровне просматриваются последовательно, от внутреннего блока к внешнему, пока не будет найден подходящий обработчик.
Пример.
#include <iostream.h>
class Obj
{ public:
Obj (char c)
{ label = c;
cout << "Конструируем объект " << label << endl;
}
~Obj();
{
сout << "Ликвидируем объект " << label << endl;
}
protected:
char label;
};
void fl() ;
void f2();
void main()
{
Obj a('a');
try
{
Obj b('b');
fl();
}
catch(float f)
{
cout << "Исключение float" << endl;
}
catch(int i)
{
cout << "Исключение int" << endl;
}
catch (... )
{
cout << "Исключение..." << endl;
}
}
void f1()
{
try
{
Obj c('c');
f2 ();
}
catch(char* pMsg)
{
cout << " Исключение char*" << endl;
}
}
void f2()
{
Obj d('d') ;
throw 10;
}
В результате работы этой программы на экран будет выведен следующий текст:
Конструируем объект а //main
Конструируем объект Ь //try
Конструируем объект с //f1
Конструируем объект d //f2
Ликвидируем объект d //выход из f2 по throw int
Ликвидируем объект с //выход из f1
Ликвидируем объект b //выход из try
Исключение int //catch int
Ликвидируем объект а //выход из main
Пример.
#include <fstream>
#include <iostream>
using namespace std;
class Hello
{ public:
Hello () {cout<< “Hello!”<<endl;}
~Hello () {cout<< “Hello!”<<endl;}
}
void fl()
{ ifstream ifs(“test.dat”);
if (!ifs)
{
cout << “Генерируем исключение” << endl;
throw “Ошибка открытия файла ”;
}
}
void f2()
{
Hello h;
f1();
}
int main()
{
try
{
cout << “In try” << endl;
f2();
cout << “From try” << endl;
}
catch(int i)
{
cout << "Исключение int" << endl;
}
catch(const char *p)
{
cout << "Исключение const char* - " <<p<< endl;
return 1;
}
catch (... )
{
cout << "Исключение..." << endl;
}
return 0;
}
В результате работы этой программы на экран будет выведен следующий текст:
In try //
Hello! //конструктор
Генерируем исключение // f1
Bye! //выход из f1, деструктор Hello
Исключение const char* - Ошибка открытия файла //
Итак, за ключевым словом throw следует выражение, которое создает объект некоторого типа: throw работает с любым типом объекта. Это значит, что вы можно "бросать" любое количество информации. Рассмотрим приведенное ниже определение класса.
#include <iostream.h>
#include <string.h>
//Except — универсальный класс
//обработки исключительных ситуаций
class Except
{
protected:
char msg[80]; //сообщение об ошибке
char file[80]; //имя файла и строка, в которой возникла ошибка
int lineNum;
public:
Except(char* pMsg, char* pFile, int nLine)
{
strncpy(msg, pMsg, sizeof msg);
msg[sizeof msg — 1] = ' \0 ' ;
strncpy (file, pFile, sizeof file};
file[sizeof file - 1] = ' \0';
lineNum = nLine;
}
virtual void display(ostream & out)
{
out << "Ошибка < " << msg << ">\n";
out << "обнаружена в строке #" << lineNum <<
" файла" << file << endl;
}
};
Генерация исключения при этом будет выглядеть следующим образом:
throw Except("Отрицательный аргумент факториала",__FILE__, __LINE__);
Соответствующий блок catch выглядит довольно просто:
void myFunc()
{
try
{
//...любой вызов
}
catch(Except &x) //захват объекта Except
{
//используем встроенную функцию-член
х.display(cerr) ;
Блок catch перехватывает исключение Except а затем использует встроенную функцию-член display() для отображения сообщения об ошибке.
Объект cerr представляет собой поток вывода для сообщений об ошибках, т.е. почти то же, что и cout. Разница между cout и cerr существенна только для профессиональных программистов.
Класс Except является универсальным для сообщений об ошибках. Этот класс, конечно, может быть расширен другими подклассами. Например, можно определить класс InvArgExcep для хранения значения некорректного аргумента в дополнение к сообщению об ошибке.
class InvArgExcept: public Except
{
protected:
int invArg;
public:
InvArgExcept (int arg, char* pFile,int nLine):
Except("Неверный аргумент", pFile, nLine)
{
invArg = arg;
}
virtual void display(ostream& out)
{
Except::display(out);
cout << "Аргумент равен " << invArg << endl;
}
};
Несмотря на то что в блоке catch указан класс Except, исключение InvArgExcept будет успешно обработано, поскольку InvArgExcept является Excepе, а функция-член display() полиморфна.