Шаг 12.
Указатель this (окончание)

    На этом шаге мы закончим изучение возможностей указателя this.

    Почти незаменимым и очень удобным указатель this становится в тех случаях, когда в теле принадлежащей классу функции нужно явно задать адрес того объекта, для которого она вызвана. Например, если в классе нужна функция, помещающая адрес выбранного объекта класса в массив или включающая конкретный объект класса в список, то такую функцию сложно написать без применения указателя this. Действительно, при организации связных списков, звеньями которых должны быть объекты класса, необходимо включать в связи звеньев указатель именно на тот объект, который в данный момент обрабатывается. Это включение должна выполнить некоторая функция-компонент класса. Однако конкретное имя включаемого объекта в момент написания этой принадлежащей классу функции недоступно, так как его гораздо позже произвольно выбирает программист, используя класс как тип данных. Можно передавать такой функции ссылку или указатель на нужный объект, но гораздо проще использовать указатель this.

    Итак, повторим, когда указатель this использован в функции, принадлежащей классу, например, с именем ZOB, то он имеет по умолчанию тип ZOB *const и всегда равен адресу того объекта, для которого вызвана компонентная функция. Если в программе для некоторого класса X определить объект:

   X  factor(5);

то при вызове конструктора класса X, создающего объект factor, значением указателя this будет &factor.

    Для пояснения возможностей указателя this рассмотрим в качестве примера класс, объекты которого формируют (образуют) двухсвязный список. В следующем тексте определяется состав класса и описываются свойства его компонентов:

//MEMBER.H - "элементы двухсвязного списка".
class member
{   
   // Адрес последнего элемента списка: 
   static member *last_memb;
   member *prev; // На предыдущий элемент списка.
   member *next; // На следующий элемент списка. 
   char bukva;   // Содержимое (значение) элемента списка. 
  public:
   // Функции для работы со списком:
   member (char ee) { bukva = ee; }      // Конструктор.
   void add(void); // Добавление элемента в конец списка.
   // Вывод на дисплей содержимого списка:
   static void reprint(void);
};

    Из объектов класса member, как из звеньев, может формироваться двухсвязный список. Схема построения списка показана на рисунке 1.


Рис.1. Список из объектов класса member

    В классе member имеется статический компонент-указатель last_memb на последний объект, уже включенный в список. Когда список пуст, значение last_memb должно быть равно нулевому указателю NULL. Связь между объектами как звеньями списка организуется с помощью указателей next и prev. Пустой список получается тогда, когда last_memb=NULL.

    Выполняет "подключение" объекта к списку компонентная функция add(). Статическая функция reprint() позволяет "перебрать" звенья списка (объекта класса member) в порядке от конца к началу и вывести значения объектов на экран дисплея. Конструктор инициализирует компонент char bukva каждого создаваемого объекта.

    Определим компонентные функции класса member:

//MEMBER.CPP - определения функций класса member. 
#include <iostream.h>
#include <stdio.h> // Для описания нулевого указателя NULL.
// Определение класса с прототипами функций: 
#include "member.h"
// Добавление элемента в конец списка: 
void member::add(void)
{ if (last_memb == NULL) 
   this -> prev = NULL; 
  else { last_memb -> next = this; 
       this -> prev = last_memb; 
       }
  last_memb = this; 
  this->next = NULL; 
}
// Вывод на дисплей содержимого списка: 
void member::reprint(void)
{ member *uk;      // Вспомогательный указатель.
  uk = last_memb; 
  if (uk == NULL) { cout << "\nСписок пуст!"; return; }
  else cout << "\nСодержимое списка:\n";
  // Цикл печати в обратном порядке значений элементов списка:
  while (uk != NULL)
   { cout << uk -> bukva << '\t'; 
     uk = uk -> prev; } 
}

    Вне класса указатель last_memb до включения в список первого элемента инициализируется нулевым значением (NULL). Поэтому первым шагом выполнения функции add() будет проверка значения last_mamb. Если он равен нулю, то в список включается первый элемент (объект), для которого указатель prev на предшествующий элемент должен быть нулевым. Для подключения объекта к уже существующему списку необходимо указателю next последнего в списке объекта присвоить значение указателя this (адрес добавляемого объекта). В качестве указателя на своего предшественника (prev) подключаемый объект получает значение last_memb. Затем последним становится обрабатываемый (только что подключенный) объект (last_memb=this;) и обнуляется его указатель next на последующий объект в списке.

    Компонентная функция reprint() описана в классе как статическая. Это никак не сказывается на ее определении. Первое действие функции - "настройка" вспомогательного указателя uk на последний включенный в список объект. Его адрес всегда является значением указателя last_memb. Если список пуст, то на этом выполнение функции завершается. В противном случае в цикле печатаются значения uk->bukva и указатель "перемещается" к предыдущему звену списка.

    В следующей программе инициализирован статический указатель last_memb, создаются объекты класса member, объединяются компонентной функцией add() в двухсвязный список, и этот список выводится на экран дисплея с помощью статической функции reprint().

//OOР12_1.СРР - статические компоненты, указатель this.
#include <iostream.h>
#include "member.cpp" // Определение класса member.
// Инициализация статического компонента (указателя):
member *member::last_memb = NULL;
void main()
{ // Формирование объектов класса member:
  member A('a'); member B('b');
  member C('c'); member D('d');
  // Вызов статической компонентной функции:
  member::reprint();
  // Включение созданных объектов в двусвязкый список:
  A.add(); B.add(); C.add(); D.add();
  // Печать в обратном порядке значений элементов списка:
  member::reprint();
}
Архив с этими тремя файлами можно взять здесь.

    Результат выполнения программы:

   Список пуст!
   Содержимое списка:
   d     с     b     а

    Обратите внимание, что все компонентные данные класса member имеют статус собственных (private) и недоступны из других частей программы. Доступ к классу обеспечивают только компонентные функции, имеющие статус public.

    На следующем шаге мы начнем знакомиться с друзьями классов.




Предыдущий шаг Содержание Следующий шаг