Реализация
Реализующие slist функции в основном просты. Единственная настоящая сложность - что делать в случае ошибки, если, например, пользователь попытается get() что-нибудь из пустого списка. Мы обсудим это в этом пункте. Здесь приводятся определения членов slist. Обратите внимание, как хранение указателя на последний элемент кругового списка дает возможность просто реализовать оба действия append() и insert():
int slist::insert(ent a) { if (last) last->next = new slink(a,last->next); else { last = new slink(a,0); last->next = last; } return 0; }
int slist::append(ent a) { if (last) last = last->next = new slink(a,last->next); else { last = new slink(a,0); last->next = last; } return 0; }
ent slist::get() { if (last == 0) slist_handler("get fromempty list"); // взять из пустого списка slink* f = last->next; ent r f->e; if (f == last) last = 0; else last->next = f->next; delete f; return f; }
Обратите внимание, как вызывается slist_handler (его описание можно найти в этом разделе). Этот указатель на имя функции используется точно так же, как если бы он был именем функции. Это является краткой формой более явной записи вызова:
(*slist_handler)("get fromempty list");
И slist::clear(), наконец, удаляет из списка все элементы:
void slist::clear() { slink* l = last; if (l == 0) return; do { slink* ll = l; l = l->next; delete ll; } while (l!=last); }
Класс slist не обеспечивает способа заглянуть в список, но только средства для вставления и удаления элементов. Однако оба класса, и slist, и slink, описывают класс slist_iterator как друга, поэтому мы можем описать подходящий итератор. Вот один, написанный в духе этого пункта:
class slist_iterator { slink* ce; slist* cs; public: slist_iterator(slist& s) { cs = &s; ce = cs->last; }
ent operator()() { // для индикации конца итерации возвращает 0 // для всех типов не идеален, хорош для указателей ent ret = ce ? (ce=ce->next)->e : 0; if (ce == cs->last) ce= 0; return ret; } };
1 2 3 4 5 6
8 8 8
|