Объективное программирование
Методическое пособие - Компьютеры, программирование
Другие методички по предмету Компьютеры, программирование
но часто классы создаются для объединения
множества элементов данных, которые внутри объекта могут
быть связаны массивом ссылок, списком, деревом и т.д..
При этом объект класса содержит ссылки
Таким образом, требуется определить некоторое множество идентичных классов с параметризованным типом внутренних элементов. То есть должна быть задана заготовка
класса (шаблон), в котором в виде параметра задан тип
(класс) входящих в него внутренних элементов данных. Тогда
при создании объекта необходимо дополнительно указывать и
конкретный тип внутренних элементов в качестве параметра.
Создание объекта сопровождается также и созданием
соответствующего конкретного класса для заданного конктретного типа.
Принятый в Си++ способ определения множества классов
с параметризованным внутренним типом данных (иначе, макроопределение) называется шаблоном (template). Синтаксис
шаблона рассмотрим на примере шаблона класса векторов,
содержащих динамический массив ссылок на переменные заданного типа.
--- параметр шаблона - класс "T", внутренний
тип данных
--- имя группы шаблонных классов
template class vector
{
inttsize;// Общее количество элеметов
intcsize;// Текущее количество элементов
T**obj;// Массив ссылок на параметризован// ные объекты типа "T"
public:
T *operator[](int);
// оператор [int] возвращает ссылку
// на параметризованный объект
// класса "T"
voidinsert(T*);// функция включения объекта типа "T"
intextract(T*);//
};
Данный шаблон может использоваться для порождения
объектов-векторов, каждый из которых хранит объекты определенного типа. Имя класса при этом составляется из имени
шаблона "vector" и имени типа данных (класса), который подставляется вместо параметра "Т":
vectora;
vectorb;
extern classtime;
vectorc;
Заметим, что транслятором при определении каждого
вектора с новым типом объектов генерируется описание нового
класса по заданному шаблону (естественно, неявно в процессе
трансляции):
class vector
{
inttsize;
intcsize;
int**obj;
public:
int *operator[](int);
voidinsert(int*);
intindex(int*);
};
Далее следует очевидное утверждение, что элементыфункции шаблона также должны быть параметризованы, то есть
генерироваться для каждого нового типа данных. Действительно, это так: элементы-функции шаблона классов в свою
очередь также являются шаблонными функциями с тем же самым
параметром. То же самое касается переопределяемых операторов:
--- параметр шаблона - класс "T", внутренний
тип данных
--- имя элемента-функции или
оператора - параметризовано
template ::operator[](int n)
{
if (n >=tsize) return(NULL);
return (obj[n]);
}
template ::index(T *pobj)
{
intn;
for (n=0; n<tsize; n++)
if (pobj == obj[n]) return(n);
return(-1);
}
Заметим, что транслятором при определении каждого
вектора с новым типом объектов генерируется набор элементовфункций по заданным шаблонам (естественно, неявно в процессе
трансляции). При этом сами шаблонные функции должны размещаться в том же заголовочном файле, где размещается
определение шаблона самого класса.
int* vector::operator[](int n)
{
if (n >=tsize) return(NULL);
return (obj[n]);
}
int vector::index(int *pobj)
{
intn;
for (n=0; n<tsize; n++)
if (pobj == obj[n]) return(n);
return(-1);
}
Шаблоны могут иметь также и параметры-константы,
которые используются для статического определения размерностей внутренних структур данных. Кроме того, шаблон
может использоваться для размещения не только ссылок на
параметризованные объекты, но и сами объекты. В качестве
примера рассмотрим шаблон для построения циклической очереди ограниченного размера для параметризованных объектов.
template class FIFO
{
intfst,lst;// Указатели на начало-конец
// очереди
Tqueue[size];// Массив объектов класса "T"
// размерности "size"
public:
Tfrom();// Функции включения-исключения
voidinto(T);//
FIFO();// Конструктор
};
template ::FIFO()
{
fst = lst = 0;
}
template ::from()
{
T work;
if (fst !=lst)
{
work = area[lst++];
lst = lst % size;
}
return(work);
}
template ::into(T obj)
{
area[fst++] = obj;
fst = fst % size;
}
Пример использования:
FIFOa;
FIFOb;
structx {};
FIFOc;
Пример сгенерированного компилятором класса для объекта "a".
class FIFO
{
intfst,lst;
doublequeue[100];
public:
doublefrom();
voidinto(double);
FIFO();
};
FIFO::FIFO()
{
fst = lst = 0;
}
double FIFO::from()
{
double work;
if (fst !=lst)
{
work = area[lst++];
lst = lst % 100;
}
return(work);
}
void FIFO::into(double obj)
{
area[fst++] = obj;
fst = fst % 100;
}