Шаг 33.
Абстрактные классы (окончание)

    На этом шаге мы закончим рассмотрение абстрактных классов.

    По сравнению с обычными классами абстрактные классы пользуются "ограниченными правами". Перечислим эти ограничения.

  1. Как говорилось, невозможно создать объект абстрактного класса.
  2. Абстрактный класс нельзя употреблять для задания типа параметра функции или в качестве типа возвращаемого функцией значения.
  3. Абстрактный класс нельзя использовать при явном приведении типов. В то же время можно определять указатели и ссылки на абстрактные классы.
  4. Объект абстрактного класса не может быть формальным параметром функции, однако формальным параметром может быть указатель абстрактного класса. В этом случае появляется возможность передавать в вызываемую функцию в качестве фактического параметра значение указателя на производный объект, заменяя им указатель на абстрактный базовый класс.

    Используя последнюю возможность, сформируем односвязный список, в элементы которого будут включаться объекты разных классов, производных от одного абстрактного класса. В качестве базового абстрактного класса выберем введенный на предыдущем шаге класс figure. Список в целом будет описываться классом chain.

    В класс chain входят (рисунок 1) в качестве компонентов:


Рис.1. Схема односвязного списка (класс chain), объединяющего объекты разных классов

    Параметр конструктора класса chain пусть имеет тип указателя на абстрактный базовый класс figure. В качестве фактических параметров будем использовать ссылки на конкретные объекты классов, производных от абстрактного класса figure. Тем самым в односвязный список включаются (рисунок 1) конкретные фигуры (квадрат - класс square, звезда - класс star).

    Текст программы со всеми включениями и определениями:

//OOР33_1.СРР - односвяэный список объектов разных классов.
#include <stdlib.h>     // NULL,...
#include <conio.h>      // getch(),...
#include <iostream.h>  
#include "point.cpp"    // Базовый класс для figure.
// Абстрактный класс, производный от point:
#include "figure.cpp"
// Класс, производный от абстрактного figure:
#include "star.cpp"
// Класс, производный от абстрактного figure:
#include "square.cpp"
// Объекты класса - фигуры, включенные в односвязный
// список:
class chain { // Объект - элемент в односвязном списке
   // Указатель на последний элемент в списке:
   static chain *last;
   // Указатель в объекте на следующий элемент:
   chain *next;
 public:
   // Указатель на фигуру, входящую в элемент списка: 
   figure *pfig;
   // Указатель на начало списка: 
   static chain *begin; 
   // Конструктор: 
   chain(figure *p);
   // Функция изображает все фигуры списка: 
   static void showAll(void);
}; // Конец определения класса.
// Внешнее описание и инициализация статических 
// компонентов класса:
chain *chain::begin = NULL; // Начало списка.
chain *chain::last = NULL;  // Последний элемент в списке.
void chain::showAll(void)   // Изображение элементов списка. 
{ chain *uk = begin;        // Настройка на начало списка. 
  while (uk != NULL)        // Цикл до конца списка.
   { uk->pfig->show('*');   // Нарисовать конкретную фигуру.
     uk = uk->next;         // Настройка на следующий элемент.
   }
}
// Конструктор создает и включает в список объект,
// связав его с конкретной фигурой из класса, производного
// от абстрактного:
chain:: chain(figure *p)  // р - адрес включаемой фигуры.
{ if (begin == NULL)      // Определили начало списка.
        begin = this;
  else last->next = this; // Связь с предыдущим элементом.
  pfig = p;               // Запоминаем адрес включаемой фигуры. 
  next = NULL;            // Пометим окончание списка. 
  last = this;            // Запоминаем адрес последнего элемента
                          // списка. 
}

void main()
{ 
  point A(10,8), B(15,20); 
  square C(A,6);
  star E(B,3);

  A.show(); getch(); // Изобразить точку - point::show().
  B.show(); getch() ; // Изобразить точку.
  // Показать квадрат - square::show():
  C.show(); getch();
  // Включить в список первый элемент - квадрат C:
  chain ca(&C);
  E.show(); getch();  // Показать звезду - star::show().
  chain ce (&E);      // Включить в список звезду.
  // Совместить фигуры - square::figure::mova():
  C.move(B); getch();
  // Убрать звезду - star::figure::hide():
  E.hide(); getch();
  // Убрать квадрат - square::figure::hide():
  C.hide(); getch();
  // Изобразитъ все фигуры из списка:
  chain::showAll();
  getch(); 
}
Текст этой программы и все описанные классы можно взять здесь.

    Статическая компонентная функция chain::showAll() обеспечивает вывод на экран изображений всех конкретных фигур, включенных в односвязный список. Важно отметить последовательность передач управления в этой функции. Указатель uk типа chain* позволяет обратиться к компоненту pf ig - указателю на абстрактный базовый класс figure. После выполнения конструктора chain() значением pfig является ссылка на объект некоторого производного от figure класса. Именно оттуда выбирается соответствующая функция show(), подменяющая чистую. виртуальную функцию figure::show(). Тем самым на экран выводится изображение конкретной фигуры. Например, функция square::show() изобразит окружность и т.д.

    В основной программе формируются точки А, B и на них, как на центрах, создаются объекты C (квадрат) и Е (эллипс). На экран выводятся и затем убираются изображения всех созданных объектов. Затем функцией showAll() рисуются все объекты, включенные в список.

    Следующий шаг мы посвятим локальным классам.




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