// объектов в соседних строках
// n-го столбца
if (TBL[i][n]->CMP(TBL[i+1][n]) <0)
{
p = TBL[i][n];
TBL[i][n] = TBL[i+1][n];
TBL[i+1][n] = p;
k++;
}
}
while (k); // Пока есть перестановки
}
//----------------------------------------------------------// Выбор элемента (i,j) в БД - возвращает неявную ссылку на
// БК объекта, по которой возможен вызов любой виртуальной
// функции
static base empty; // Пустой объект для ошибочного выбора
base& table::opertor()(int i,int j)
{
if (i<0 || i >= nr) return(empty);
if (j<0 || j >= nc) return(empty);
return (*TBL[i][j]); // Возвратить неявную ссылку на объект
}
//--------------------------------------------------------// Пример работы с классом РБД
void main()
{
int i,j;
table R; // Создание БД
for (i=0; i<10; i++)
R.append(); // Ввод 10-ти строк
R.sort(1); // Сортировка по первому столбцу
scanf("%d %d", &i, &j); // Вывод значения элемента
R(i,j).PUT();
R(1,2) + "1234"; // Операция "объект + строка"
// для элемента 1,2
}
Лекция 9. Шаблоны.
-----------------
Довольно часто классы создаются для объединения
множества элементов данных, которые внутри объекта могут
быть связаны массивом ссылок, списком, деревом и т.д..
При этом объект класса содержит ссылки
Таким образом, требуется определить некоторое множество идентичных классов с параметризованным типом внутренних элементов. То есть должна быть задана заготовка
класса (шаблон), в котором в виде параметра задан тип
(класс) входящих в него внутренних элементов данных. Тогда
при создании объекта необходимо дополнительно указывать и
конкретный тип внутренних элементов в качестве параметра.
Создание объекта сопровождается также и созданием
соответствующего конкретного класса для заданного конктретного типа.
Принятый в Си++ способ определения множества классов
с параметризованным внутренним типом данных (иначе, макроопределение) называется шаблоном (template). Синтаксис
шаблона рассмотрим на примере шаблона класса векторов,
содержащих динамический массив ссылок на переменные заданного типа.
--- параметр шаблона - класс "T", внутренний
¦ тип данных
¦ --- имя группы шаблонных классов
template <class T> class vector
{
int tsize; // Общее количество элеметов
int csize; // Текущее количество элементов
T **obj; // Массив ссылок на параметризован // ные объекты типа "T"
public:
T *operator[](int);
// оператор [int] возвращает ссылку
// на параметризованный объект
// класса "T"
void insert(T*); // функция включения объекта типа "T"
int extract(T*); //
};
Данный шаблон может использоваться для порождения
объектов-векторов, каждый из которых хранит объекты определенного типа. Имя класса при этом составляется из имени
шаблона "vector" и имени типа данных (класса), который подставляется вместо параметра "Т":
vector<int> a;
vector<double> b;
extern class time;
vector<time> c;
Заметим, что транслятором при определении каждого
вектора с новым типом объектов генерируется описание нового
класса по заданному шаблону (естественно, неявно в процессе
трансляции):
class vector<int>
{
int tsize;
int csize;
int **obj;
public:
int *operator[](int);
void insert(int*);
int index(int*);
};
Далее следует очевидное утверждение, что элементыфункции шаблона также должны быть параметризованы, то есть
генерироваться для каждого нового типа данных. Действительно, это так: элементы-функции шаблона классов в свою
очередь также являются шаблонными функциями с тем же самым
параметром. То же самое касается переопределяемых операторов:
--- параметр шаблона - класс "T", внутренний
¦ тип данных
¦ --- имя элемента-функции или
¦ ¦ оператора - параметризовано
¦ ¦
template <class T> T* vector<T>::operator[](int n)
{
if (n >=tsize) return(NULL);
return (obj[n]);
}
template <class T> int vector<T>::index(T *pobj)
{
int n;
for (n=0; n<tsize; n++)
if (pobj == obj[n]) return(n);
return(-1);
}
Заметим, что транслятором при определении каждого
вектора с новым типом объектов генерируется набор элементовфункций по заданным шаблонам (естественно, неявно в процессе
трансляции). При этом сами шаблонные функции должны размещаться в том же заголовочном файле, где размещается
определение шаблона самого класса.
int* vector<int>::operator[](int n)
{
if (n >=tsize) return(NULL);
return (obj[n]);
}
int vector<int>::index(int *pobj)
{
int n;
for (n=0; n<tsize; n++)
if (pobj == obj[n]) return(n);
return(-1);
}
Шаблоны могут иметь также и параметры-константы,
которые используются для статического определения размерностей внутренних структур данных. Кроме того, шаблон
может использоваться для размещения не только ссылок на
параметризованные объекты, но и сами объекты. В качестве
примера рассмотрим шаблон для построения циклической очереди ограниченного размера для параметризованных объектов.
template <class T><int size> class FIFO
{
int fst,lst; // Указатели на начало-конец
// очереди
T queue[size]; // Массив объектов класса "T"
// размерности "size"
public:
T from(); // Функции включения-исключения
void into(T); //
FIFO(); // Конструктор
};
template <class T><int size> FIFO<T><int>::FIFO()
{
fst = lst = 0;
}
template <class T><int size> T FIFO<T><int>::from()
{
T work;
if (fst !=lst)
{
work = area[lst++];
lst = lst % size;
}
return(work);
}
template <class T><int size> void FIFO<T><int>::into(T obj)
{
area[fst++] = obj;
fst = fst % size;
}
Пример использования:
FIFO<double><100> a;
FIFO<int><20> b;
struct x {};
FIFO<x><50> c;
Пример сгенерированного компилятором класса для объекта "a".
class FIFO<double><100>
{
int fst,lst;
double queue[100];
public:
double from();
void into(double);
FIFO();
};
FIFO<double><100>::FIFO()
{
fst = lst = 0;
}
double FIFO<double><100>::from()
{
double work;
if (fst !=lst)
{
work = area[lst++];
lst = lst % 100;
}
return(work);
}
void FIFO<double><100>::into(double obj)
{
area[fst++] = obj;
fst = fst % 100;
}