Программа 66. Шаблон классов динамических массивов
Шаблон классов динамических массивов похож на шаблон классов векторов. Добавлена возможность устанавливать размер массива по умолчанию и функция нахождения максимального элемента массива.
// Файл TmplDArr.cpp
#include <stdlib.h> // Для rand()
#include <time.h>
#include <iostream>
#include<Windows.h> // Для функции CharToOem
char Buff[500]; // Буфер для преобразования русских букв
char* Rus(char* in) // Функция для преобразования русских букв
{
CharToOem(in, Buff); // Функция CharToOem преобразует строку in
return Buff; // в строку Buff, используя кодировку DOS
}
using namespace std;
template <class T, int size = 64> // 64 – значение по умолчанию для size
class DynArr { // Шаблон классов динамических массивов
T* data; // Массив элементов
int n; // Количество элементов
public:
DynArr() // Конструктор
{ data = new T[n = size]; }
~DynArr() // Деструктор
{delete[] data;}
T& operator[](int i) // Доступ к элементу
{ return data[i];}
int SizeArr() // Размер массива
{return n;}
T GetMax(); // Возвращает значение максимального элемента
};
// Определение функции-члена шаблона классов
template <class D, int sz> // Имена параметров шаблона в определении
D DynArr<D, sz>::GetMax() // могут отличатся от их имен в объявлении
{
D max = data[0];
for(int i = 1; i < n; i++)
if(data[i] > max)
max = data[i];
return max;
}
В главной функции создаются два динамических массива: x с размером по умолчанию и y заданного размера. Массивы заполняются случайными числами, генерируемыми функцией int rand(void). Для того, чтобы при каждом запуске программы генерировались различные последовательности чисел, вызывается функция
void srand(unsigned seed);
Ее аргумент задает начальную точку в последовательности псевдослучайных чисел, генерируемых rand. Для получения значения seed использована объявленная в time.h функция
time_t time(time_t *timer);
возвращающая количество секунд, прошедших от полуночи 1 января 1970 г. Это значение записывается также по адресу timer или игнорируется, если timer=NULL. Тип time_t – это новое обозначение для long, введенное с помощью typedef.
Обработка созданных массивов состоит в том, что выводятся значения их максимальных элементов.
int main()
{
srand(unsigned(time(NULL))); // Инициализация датчика сл. чисел
DynArr<double> x; // Массив x из 64 double
DynArr<int, 20> y; // Массив y из 20 int
int i;
for(i = 0; i < x.SizeArr(); i++) // Заполнение массива x
x[i] = rand();
cout << Rus("Количество элементов в x: ") << x.SizeArr();
cout << Rus(", максимальное из x: ") << x.GetMax() << endl;
for(i = 0; i < y.SizeArr(); i++) // Заполнение массива y
y[i] = rand();
cout << Rus("Количество элементов в y: ") << y.SizeArr();
cout << Rus(", максимальное из y: ") << y.GetMax();
cin.get();
return 0;
}
При одном из запусков программа напечатала:
Количество элементов в x: 64, максимальное из x: 32635
Количество элементов в y: 20, максимальное из y: 30486
Обработка исключений
Исключение – это особая ситуация, возникающая в ходе работы программы. Встроенными особыми ситуациями являются «деление на нуль», «конец файла», «переполнение при вычислении». В языке C++ любое состояние, достигнутое в процессе выполнения программы, можно заранее определить как особую ситуацию (исключение) и предусмотреть действия, которые нужно выполнить при её возникновении.
Для реализации механизма обработки исключений в языке C++ есть три ключевых слова:
try (пробовать, пытаться, испытывать),
catch (ловить, обнаруживать),
throw (бросать, посылать).
Эти ключевые слова позволяют выделить контролируемый блок, зафиксировать исключение и назначить обработчик исключения. Схема обработки исключений имеет вид:
try{ // Контролируемый блок
ОПЕРАТОРЫ // Обычные операторы
throw ВЫР; // Передача управления обработчику исключений
ОПЕРАТОРЫ
}
catch(ТИП_ИСКЛЮЧЕНИЯ ИМЯ){ // Обработчик исключений
ОПЕРАТОРЫ
}
Программист должен предусмотреть передачу управления оператору throw при возникновении исключения. Оператор throw прерывает естественный ход работы программы и передает управление в тот блок catch, у которого ТИП_ИСКЛЮЧЕНИЯ соответствует типу ВЫР, при этом объект ИМЯ инициализируется значением ВЫР.
В приводимой ниже программе демонстрируется обработка исключений в задаче о нахождении наибольшего общего делителя двух целых чисел x и y.
Программа 67. Расчет НОД
Справедливы следующие свойства НОД двух чисел:
Nod(x, y) = x, если х = у;
Nod(x, y) = Nod(y, x - y), если х > у,
Nod(x, y) = Nod(y, x);
если х <= 0, или у <= 0, то Nod не определён.
Исключительными ситуациями при расчете НОД является равенство нулю или отрицательное значение одного из чисел.
Для передачи информации из точки, где возникло исключение в обработчик исключений, введём специальный класс Except, членами которого будут две целые переменные m, n, хранящие значение х и у, и строка mess с сообщением о характере особой ситуации.
//Файл Exeption.cpp
#include <iostream.h>
struct Except{ // Класс для информации об исключении
int m, n; // Числа
char* mess; // Описание исключения
Except(int a, int b, char* msg) // Конструктор
{m = a; n = b; mess = msg;}
};
int Nod(int x, int y)
{
if(x == 0 || y == 0) throw Except(x, y, "Zero!");
if(x < 0) throw Except(x, y, "Negative argument 1.");
if(y < 0) throw Except(x, y, "Negative argument 2.");
if(x == y) return x;
if(x < y) return Nod(y, x);
return Nod(y, x - y);
}
void main()
{
try{
cout << "\nNod(66, 44) = " << Nod(66, 44)<< '\n';
cout << "\nNod(0, 7) = " << Nod(0, 7)<< '\n';
cout << "\nNod(-12, 8) = " << Nod(-12, 8)<< '\n';
}
// Обработчик исключений. В d содержится информация об исключении
catch(Except d){
cerr << d.mess << " x = " << d.m << ", y = " << d.n <<'\n';
}
cin.get();
}
Здесь после throw стоит вызов конструктора класса Except, который создаёт безымянный объект, инициализированный значением аргументов Nod и текстом сообщения. Этот объект будет передан в блок catch и использован для инициализации параметра d, тем самым информация об исключении становится доступной в обработчике исключений. Обработка исключения состоит в выводе в поток для ошибок cerr сведений о возникшей проблеме, передаваемых через объект d.
Программа выдает:
Nod(66, 44) = 22
Zero! x = 0, y = 7
Здесь исключение возникает при вычислении Nod(0, 7). Оператор throw прерывает выполнение функции Nod и передает управление в блок catch. Причем отыскивается тот из нескольких возможых блоков catch, которые могут стоять за блоком try, у которого тип объекта-исключения соответствует генерируемому типу исключения в операторе throw. Оператор вида
catch(…){ // Обработчик исключений
ИНСТРУКЦИИ
}
перехватывает исключения любых типов.