Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
c++book1.doc
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
2 Мб
Скачать
☆

6.7 Индексирование

Чтобы задать смысл индексов для объектов класса, исполь­зуется функция operator[]. Второй параметр (индекс) функции operator[] может быть любого типа. Это позволяет определять ассоциативные массивы и т.п. В качестве примера давайте пере­пишем пример из #2.3.10, где при написании небольшой програм­мы для подсчета числа вхождений слов в файле применялся ассо­циативный массив. Там использовалась функция. Здесь определяется надлежащий тип ассоциативного массива:

struct pair (*

char* name;

int val;

*);

class assoc (*

pair* vec;

int max;

int free;

public:

assoc(int);

int& operator[](char*);

void print_all();

*);

В assoc хранится вектор пар pair длины max. Индекс пер­вого неиспользованного элемента вектора находится в free. Конструктор выглядит так:

assoc::assoc(int s)

(*

max = (s<16) ? s : 16;

free = 0;

vec = new pair[max];

*)

При реализации применяется все тот же простой и неэффек­тивный метод поиска, что использовался в #2.3.10. Однако при переполнении assoc увеличивается:

#include <string.h>

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; i<max; i++) nvec[i] = vec[i];

delete vec;

vec = nvec;

max = 2*max;

*)

pp = &vec[free++];

pp->name = new char[strlen(p)+1];

strcpy(pp->name,p);

pp->val = 0; // начальное значение: 0

return pp->val;

*)

Поскольку представление assoc скрыто, нам нужен способ его печати. В следующем разделе будет показано, как опреде­лить подходящий итератор, а здесь мы используем простую функ­цию печати:

vouid assoc::print_all()

(*

for (int i = 0; i<free; i++)

cout << vec[i].name << ": " << vec[i].val << "\n"; *)

Мы можем, наконец, написать простую главную программу:

main() // считает вхождения каждого слова во вводе

(*

const MAX = 256; // больше самого большого слова

char buf[MAX];

assoc vec(512);

while (cin>>buf) vec[buf]++;

vec.print_all();

*)

6.8 Вызов Функции

Вызов функции, то есть запись выражение(список_выраже­ний), можно проинтерпретировать как бинарную операцию, и операцию вызова можно перегружать так же, как и другие опера­ции. Список параметров функции 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 (i<cs->free)? &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";

*)

0 Итераторный тип вроде этого имеет преимущество перед на-

бором функций, которые выполняют ту же работу: у него есть

собственные закрытые данные для хранения хода итерации. К то­му же обычно существенно, чтобы одновременно могли работать много итераторов этого типа.

Конечно, такое применение объектов для представления итераторов никак особенно с перегрузкой операций не связано. Многие любят использовать итераторы с такими операциями, как first(), next() и last() (первый, следующий и последний).

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]