Смекни!
smekni.com

Объективное программирование (стр. 10 из 10)

// объектов в соседних строках

// 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;

}