Вход/Регистрация
Программирование. Принципы и практика использования C++ Исправленное издание
вернуться

Страуструп Бьерн

Шрифт:

Аналогично можем перенести Зевса в правильный список греческих богов.

Link* p = find(norse_gods,"Zeus");

if (p) {

erase(p);

insert(greek_gods,p);

}

Вы заметили ошибку? Она довольно тонкая (конечно, если вы не работаете со списками непосредственно). Что, если на опустошенный с помощью функции

erase
узел ссылался один из узлов списка
norse_gods
? Разумеется, на самом деле этого не было, но в жизни бывает всякое, и хорошая программа должна это учитывать.

Link* p = find(norse_gods, "Zeus");

if (p) {

if (p==norse_gods) norse_gods = p–>succ;

erase(p);

greek_gods = insert(greek_gods,p);

}

Заодно мы исправили и вторую ошибку: вставляя Зевса перед первым греческим богом, мы должны установить на него указатель списка. Указатели — чрезвычайно полезный и гибкий, но очень тонкий инструмент. В заключение распечатаем наш список.

void print_all(Link* p)

{

cout << "{ ";

while (p) {

cout << p–>value;

if (p=p–>succ) cout << ", ";

}

cout << " }";

}

print_all(norse_gods);

cout<<"\n";

print_all(greek_gods);

cout<<"\n";

Результат должен быть следующим:

{ Freia, Odin, Thor }

{ Zeus, Poseidon, Ares, Athena, Hera }

17.10. Указатель this

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

Link*
для доступа к данным, хранящимся в этом объекте. Такие функции обычно являются членами класса. Можно ли упростить класс
Link
(или использование списка), предусмотрев соответствующие члены класса?

Может быть, сделать указатели закрытыми, чтобы только функции-члены класса могли обращаться к ним? Попробуем.

class Link {

public:

string value;

Link(const string& v,Link* p = 0,Link* s = 0)

:value(v), prev(p),succ(s) { }

Link* insert(Link* n); // вставляет n перед данным объектом

Link* add(Link* n); // вставляет n после данного объекта

Link* erase; // удаляет данный объект из списка

Link* find(const string& s); // находит s в списке

Link* advance(int n) const; // удаляет n позиций

// из списка

Link* next const { return succ; }

Link* previous const { return prev; }

private:

Link* prev;

Link* succ;

};

Этот фрагмент выглядит многообещающе. Мы определили операции, не изменяющие состояние объекта класса

Link
, с помощью константных функций-членов. Мы добавили (не модифицирующие) функции
next
и
previous
, чтобы пользователи могли перемещаться по списку, — поскольку непосредственный доступ к указателям
succ
и
prev
теперь запрещен. Мы оставили значение узла в открытом разделе класса, потому что (пока) у нас не было причины его скрывать; ведь это просто данные.

Попробуем теперь реализовать функцию

Link::insert
, скопировав и модифицировав предыдущий вариант.

Link* Link::insert(Link* n) // вставляет n перед p; возвращает n

{

Link* p = this; // указатель на данный объект

if (n==0) return p; // ничего не вставляем

if (p==0) return n; // ничего не вставляем

n–>succ = p; // p следует за n

  • Читать дальше
  • 1
  • ...
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: