Назад | Начало урока | Вперед
Содержание

Глава 02

Исследование параметризованных классов

Вверх

Обзор параметризованных классов

Прежде чем начинать строить параметризованные контейнерные классы,
необходимо хотя бы обзорно познакомиться с шаблонами классов. Определяя
параметризованный класс, вы создаете класс, который определяет все
алгоритмы, используемые этим классом, однако фактический тип данных,
над которыми производятся манипуляции, будет указан в качестве параметра
при конкретизации объектов этого класса. Компилятор автоматически
сгенерирует соответствующий объект на основании указанного вами типа.

Общая форма декларации параметризованного класса приведена ниже:

template<class Ttype>class class-name {

. . .
}

Здесь Ttype представляет собой имя типа шаблона, которое в каждом случае
конкретизации будет замещаться фактическим типом данных
. При необходимости
вы можете определить более одного параметризованного типа данных, используя
список с разделителем - запятой. В пределах определения класса имя Ttype
можно использовать в любом месте.

Создав параметризованный класс, вы можете создать конкретную реализацию
этого класса, используя следующую общую форму:

class-name <type> ob;

Здесь type представляет собой имя типа данных, над которыми фактически
оперирует класс
, и заменяет собой переменную Ttype.

Наконец функции-члены параметризованного класса автоматически являются
параметризованными. Их не обязательно декларировать как параметризованные
с помощью ключевого слова template.

Вверх

Ограниченные массивы

Простейшим примером контейнерного класса является ограниченный или
защищенный массив. Как вы знаете во время выполнения кода можно выйти
за границу массива или не дойти до нее без генерации сообщений об ошибках
времени выполнения. Однако эту проблему можно успешно решить. Для этого
необходимо создать класс который содержит массив, и разрешить доступ
к массиву только через перегруженный индексирующий оператор [].
В функции operator[]() вы можете перехватывать индекс, выходящий за рамки
диапазона массива. Поскольку механизм проверки границ будет одинаков
для всех типов данных, имеет смысл создание параметризованного ограниченного
массива, который вы сможете использовать каждый раз когда вам потребуется
защищенный массив. Как вы увидите далее ограниченный параметризованный
массив является простейшим, но не смотря на это одним из наиболее полезных
контейнерных классов.
Как уже упоминалось, построение ограниченного параметризированного
массива требует перегрузки оператора []. Если вы еще не знакомы
с перегрузкой этого оператора, вам поможет материал следующего раздела.

Перегрузка оператора []

В С++ оператор [] при перегрузке считается бинарным оператором.
[] может быть перегружен только функцией-членом. Общая форма функции-члена
operator[]() приведена ниже :

type class-name::operator[](int index)
{

// ...
}

Чисто технически, параметр не обязательно должен принадлежать к типу int
Однако функции operator[](), как правило используются для обеспечения
индексации массивов, а для этого обычно используются целые значения.
Как правило функция operator[]() возвращает значение того же типа,
что и тип данных, хранящихся в индексируемом массиве.

Принцип работы оператора [] проще всего понять на примере объекта
с именем ob, проиндексированного следующим образом :

ob[9]

Индекс этого массива будет транслироваться в следующий вызов функции
operator[]() :

operator[](9)

Таким образом выражение, используемое в качестве оператора индексации,
передается функции operator[]() как явный параметр.Указатель this
будет указывать на ob, объект, сгенерировавший этот вызов.

Функцию operator[]() можно разработать таким образом, чтобы оператор []
можно было использовать как в левой, так и в правой части оператора
присваивания. Для этого следует определить возвращаемое значение
функции operator[]() как ссылку, и возвращать ссылку на указанный
элемент массива. В этом случае будут корректны следующие типы утверждений:

ob[9] = 10;
x = ob[9]

Построение параметризованного ограниченного массива

Нижеприведенная программа создает параметризованный ограниченный массив и
иллюстрирует его использование. Обратите внимание что функция operator[]()
возвращает ссылку, которая позволяет использовать ее в любой части
утверждения присваивания.


//параметризированный ограниченный массив

#include<iostream.h>
#include<stdlib.h>

//параметризированный класс ограниченного массива

template <class Atype> class atype
{

Atype *a; //указатель на тип Atype
int length;
public:
atype(int size); //конструктор
~atype() {delete [] a;} //деструктор встроенный
Atype &operator[](int i);
};

//конструктор для atype
template <class Atype> atype ::atype(int size)
{

register int i;
length = size;
a=new Atype[size]; //создали массив в динамической памяти
if(!a)
{
cout<<"Nevozmoghno vydelity massiv. \n";
exit(1);
}
//инициализация нулем
for(i=0;i<size;i++) a[i]=0;
}

//обеспечение диапазона проверки для atype
template <class Atype> Atype &atype<Atype>::operator [](int i)
{

if(i<0||i>length-1)
{
cout << "\n Znachenie s indexom.";
cout << i <<" Vyhodit za predely diapazona \n";
exit(1);
}
return a[i];
}

main()
{

atype<int> intob(20);//массив целых чисел
atype<double> doubleob(20);//массив типа double
int i;

cout << "Int array:";
for(i=0;i<20;i++) intob[i]=i;
for(i=0;i<20;i++) cout << intob[i] << " ";
cout << endl;

cout << " Double array:";
for(i=0;i<20;i++) doubleob[i]=(double)i*3.14;
for(i=0;i<20;i++) cout << doubleob[i] << " ";
cout << endl;

intob[45]=100;//generate run-time error

return 0;

}


Результат:

Int array:0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 1 7 18 19

Double array:0 3.14 6.28 9.42 12.56 15.7 18.84 21.98 25.12 28.26 31.4 34.54 37.68 40.82 43.96 47.1 50.24 53.38 56.52 59.66

Значение с индексом 45 Выходит за пределы диапазона

Эта программа реализует параметризованный тип защищенного массива,
а затем демонстрирует его использование, создавая массив целых и
массив переменных типа double.(Можно попытаться создать и массивы других
типов).

Как показывает этот пример параметризованные классы позволяют
один раз написать и отладить код, который после этого можно использовать
с данными любых типов без необходимости его дальнейшей переработки
для каждого конкретного приложения.

Принцип работы программы таков: Пространство для массива выделяется
динамически, а соответствующий указатель на этот адрес памяти хранится
в переменной a.

a=new Atype[size]; //создали массив в динамической памяти

Размер массива передается в качестве параметра
конструктору atype и хранится в переменной lenght.

template <class Atype> atype <Atype>::atype(int size)
{

register int i;
length = size;
. . .
}

Таким образом, вы должны указывать размер массива при его создании.
Поскольку создавать можно массивы всевозможных размеров, atype можно
применять в самом широком диапазоне приложений. Однако, если вы заведомо
знаете, что будете работать с массивами одного размера, рекомендуется
использвать для atype массивы фиксированной длины, так как это
несколько ускорит время выполнения.


Назад | Начало урока | Вверх | Вперед
Содержание

Hosted by uCoz