![]() Главная страница Случайная страница КАТЕГОРИИ: АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника |
Листинг 10.3
#include int assoc:: operator[](char* p) /* работа с множеством пар " pair": поиск p, возврат ссылки на целую часть его " pair" делает новую " pair", если p не встречалось */ { register pair* pp; for (pp = & vec[free-1]; vec < = pp; pp--) if (strcmp(p, pp-> name)==0) return pp-> val; if (free == max) { // переполнение: вектор увеличивается pair* nvec = new pair[max*2]; for (int i = 0; iname = new char [strlen(p)+1]; i++); strcpy(pp-> name, p); pp-> val = 0; // начальное значение: 0 return pp-> val; }
Поскольку представление assoc скрыто, нужен способ его печати. Здесь воспользуемся простой функцией печати:
vouid assoc:: print_all() { for (int i = 0; i> buf) vec[buf]++; vec.print_all(); } Вызов Функции. Вызов функции, то есть запись выражение(список_выражений), можно проинтерпретировать как бинарную операцию, и операцию вызова можно перегружать так же, как и другие операции. Список параметров функции operator() вычисляется и проверяется в соответствие с обычными правилами передачи параметров. Перегружающая функция может оказаться полезной главным образом для определения типов с единственной операцией и для типов, у которых одна операция настолько преобладает, что другие в большинстве ситуаций можно не принимать во внимание. Для типа ассоциативного массива assoc мы не определили итератор. Это можно сделать, определив класс assoc_iterator, работа которого состоит в том, чтобы в определенном порядке поставлять элементы из assoc. Итератору нужен доступ к данным, которые хранятся в assoc, поэтому он сделан другом:
class assoc { friend class assoc_iterator; pair* vec; int max; int free; public: assoc(int); int& operator[](char*); };
Итератор определяется как
class assoc_iterator { assoc* cs; // текущий массив assoc int i; // текущий индекс public: assoc_iterator(assoc& s) { cs = & s; i = 0; } pair* operator()() { return (ifree)? & cs-> vec[i++]: 0; } };
Надо инициализировать assoc_iterator для массива assoc, после чего он будет возвращать указатель на новую pair из этого массива всякий раз, когда его будут активизировать операцией (). По достижении конца массива он возвращает 0:
main() // считает вхождения каждого слова во вводе { const MAX = 256; // больше самого большого слова char buf[MAX]; assoc vec(512); while (cin> > buf) vec[buf]++; assoc_iterator next(vec); pair* p; while (p = next()) cout < < p-> name < < ": " < < p-> val < < " \n"; }
Итераторный тип вроде этого имеет преимущество перед набором функций, которые выполняют ту же работу: у него есть собственные закрытые данные для хранения хода итерации. К тому же обычно существенно, чтобы одновременно могли работать много итераторов этого типа. Конечно, такое применение объектов для представления итераторов никак особенно с перегрузкой операций не связано. Многие любят использовать итераторы с такими операциями, как first(), next() и last() (первый, следующий и последний).
|