Литмир - Электронная Библиотека
A
A

  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);

}

И наконец, выведем список на печать.

void print_all(Link* p)

{

  cout << "{ ";

  while (p) {

    cout << p–>value;

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

  }

  cout << " }";

}

print_all(norse_gods);

cout<<"\n";

print_all(greek_gods);

cout<<"\n";

В итоге получим следующий результат:

{ Freia, Odin, Thor }

{ Zeus, Poseidon, Ares, Athena, Hera }

Какая из этих версий лучше: та, в которой функция

insert()
и другие являются функциями-членами, или та, в которой они не принадлежат классу? В данном случае это не имеет значения, но вспомните, что было написано в разделе 9.7.5.

Следует отметить, что мы создали не класс списка, а только класс узла. В результате мы вынуждены следить за тем, какой указатель ссылается на первый элемент. Эти операции можно было бы сделать лучше, определив класс

List
, но структура класса, продемонстрированная выше, является общепринятой. Стандартный класс
list
рассматривается в разделе 20.4.

Задание

Это задание состоит из двух частей. Первые упражнения должны дать вам представление о динамических массивах и их отличии от класса

vector
.

1. Разместите в свободной памяти массив, состоящий из десяти чисел типа

int
, используя оператор
new
.

236
{"b":"847443","o":1}