Программирование. Принципы и практика использования C++ Исправленное издание, стр. 235
Аналогично можем перенести Зевса в правильный список греческих богов.
Link* p = find(norse_gods,"Zeus");if (p) { erase(p); insert(greek_gods,p);}Вы заметили ошибку? Она довольно тонкая (конечно, если вы не работаете со списками непосредственно). Что, если на опустошенный с помощью функции
erase()norse_godsLink* 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;};Этот фрагмент выглядит многообещающе. Мы определили операции, не изменяющие состояние объекта класса
Linknext()previous()succprevПопробуем теперь реализовать функцию
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 if (p–>prev) p–>prev–>succ = n; n–>prev = p–>prev; // предшественник p становится // предшественником n p–>prev = n; // n становится предшественником p return n;}Как получить указатель на объект, для которого была вызвана функция
Link::insert()thisthispLink* Link::insert(Link* n) // вставляет n перед p; возвращает n{ if (n==0) return this; if (this==0) return n; n–>succ = this; // этот объект следует за n if (this–>prev) this–>prev–>succ = n;