С++ - язык, который изучается постепенно.Курсоры и разреженные массивы


Материалы книги получены с http://www.itlibitum.ru/

Курсоры и разреженные массивы

Итак, вторая попытка. Наша основная цель - чтобы операторная функция operator[] возвращала нечто, обладающее следующими свойствами:

1. Оно должно преобразовываться к типу содержимого массива.

2. Оно может использоваться в левой части операции присваивания для изменения содержимого соответствующей ячейки.

Это «нечто» представляет собой особый класс, который называется курсором (cursor). Ниже показан уже знакомый разреженный массив с курсором в операторной функции operator[]:

class ArrayCursor;

class SparseArray {

friend class ArrayCursor;

private:

struct Node {

Index index;

Foo* content;

Node* next;

Node(Index i, Foo* c, Node* n) : index(i), content(c), next(n) {};

};

Node* cells;

public:

SparseArray() : cells(NULL) {}

ArrayCursor operator[](Index i);

};

class ArrayCursor {

friend class SparseArray;

private:

SparseArray& array; // Обратный указатель на массив-владелец

Index index; // Элемент, представленный курсором

SparseArray::Node* node; // Если существует индекс, отличный от NULL

// Конструкторы объявлены закрытыми, поэтому пользоваться ими

// может только SparseArray. Первый конструктор используется, когда

// индекс еще не существует, а второй - когда индекс уже присутствует

// в массиве.

ArrayCursor(SparseArray& arr, Index i)

: array(arr), index(i), node(NULL) {}

ArrayCursor(SparseArray& arr, SparseArray::Node* n)

: array(arr), node(n), index(n->index) {}

public:

// Следующий оператор = позволяет преобразовать присваивание курсору в

// присваивание соответствующему элементу массива.

ArrayCursor& operator=(Foo* foo);

};

ArrayCursor& ArrayCursor::operator=(Foo* foo) {

if (node == NULL) { // Индекс не существует

node = new SparseArray::Node(index, foo, array.cells);

array.cells = node;

}

else

// Индекс уже существует, изменить значение элемента

node->content = foo;

return *this;

}

ArrayCursor SparseArray::operator[](Index i)

{

SparseArray::Node* n = cells;

while (n != NULL)

if (n->index = i)

return ArrayCursor(*this, n); // Существует

else

n = n->next;

return ArrayCursor(*this, i); // Еще не существует

}

Ого! Что же происходит в этом хитроумном коде? Все волшебство заключено в двух операторных функциях, SparseArray::operator[]() и ArrayCursor::operator=(). SparseArray::

operator[]() возвращает ArrayCursor независимо от того, существует индекс или нет (об этом

ArrayCursor узнает по тому, какой конструктор был выбран). ArrayCursor::operator=(Foo*)

делает одно из двух: если индекс уже существует, элемент изменяется, а если не существует - он динамически добавляется в массив. В этом проявляется вся суть курсорности (курсоризма?): перегруженный оператор = выполняет присваивание не для самого курсора, а для структуры данных, от которой происходит курсор. Теперь присваивание работает независимо от того, существует индекс или нет.

array[Index(17, 29)] = new Foo; // Добавляет индекс

array[Index(17, 29)] = new Foo; // Изменяет значение с заданным индексом

Неплохо для часовой работенки, не правда ли? Наш массив работает совсем как настоящий. Почти.


Назад    Содержание    Далее    

Copyright 2005. Климов Александр. All Right Reserved.
Сайт создан в системе uCoz