Шрифт:
if (p–>prev) p–>prev–>succ = n;
n–>prev = p–>prev; // предшественник p становится
// предшественником n
p–>prev = n; // n становится предшественником p
return n;
}
Как получить указатель на объект, для которого была вызвана функция
Link::insert
? Без помощи языка это сделать невозможно. Однако в каждой функции-члене существует идентификатор this
, являющийся указателем на объект, для которого она вызывается. A в качестве альтернативы мы могли бы просто писать this
вместо p
.
Link* 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;
n–>prev = this–>prev; // предшественник этого объекта
// становится
// предшественником объекта n
this–>prev = n; // n становится предшественником этого
// объекта
return n;
}
Это объяснение выглядит немного многословным, но мы не обязаны упоминать, что указатель
this
обеспечивает доступ к члену класса, поэтому код можно сократить.
Link* Link::insert(Link* n) // вставляет n перед p; возвращает n
{
if (n==0) return this;
if (this==0) return n;
n–>succ = this; // этот объект следует за n
if (prev) prev–>succ = n;
n–>prev = prev; // предшественник этого объекта
// становится
// предшественником объекта n
prev = n; // n становится предшественником этого
// объекта
return n;
}
Иначе говоря, при каждом обращении к члену класса происходит неявное обращение к указателю
this
. Единственная ситуация, в которой его необходимо упомянуть явно, возникает, когда нужно сослаться на весь объект. Обратите внимание на то, что указатель
this
имеет специфический смысл: он ссылается на объект, для которого вызывается функция-член. Он не указывает на какой-то из ранее использованных объектов. Компилятор гарантирует, что мы не сможем изменить значение указателя this
в функции-члене. Рассмотрим пример.
struct S {
// ...
void mutate(S* p)
{
this = p; // ошибка: указатель this не допускает изменений
// ...
}
};
17.10.1. Еще раз об использовании списков
Сталкиваясь с вопросами реализации, мы можем увидеть, как выглядит использование списка.
Link* norse_gods = new Link("Thor");
norse_gods = norse_gods–>insert(new Link("Odin"));
norse_gods = norse_gods–>insert(new Link("Zeus"));
norse_gods = norse_gods–>insert(new Link("Freia"));
Link* greek_gods = new Link("Hera");
greek_gods = greek_gods–>insert(new Link("Athena"));
greek_gods = greek_gods–>insert(new Link("Mars"));
greek_gods = greek_gods–>insert(new Link("Poseidon"));
Это очень похоже на предыдущие фрагменты нашей программы. Как и раньше, исправим наши ошибки. Например, укажем правильное имя бога войны.
Link* p = greek_gods–>find("Mars");
if (p) p–>value = "Ares";
Перенесем Зевса в список греческих богов.
Link* p2 = norse_gods–>find("Zeus");
if (p2) {
if (p2==norse_gods) norse_gods = p2–>next;
p2–>erase;
greek_gods = greek_gods–>insert(p2);
}
И наконец, выведем список на печать.