5.2. Организация списка объектов различного типа

Определим класс, объектом которого является список объектов различного типа. Пусть, для определенности, список состоит из точек и отрезков. Точка задается двумя целыми координатами, а отрезок – четырьмя целыми координатами.

Класс точки зададим как класс элемента списка, имеющего помимо координат указатель на следующий элемент, конструктор и виртуальную функцию вывода на экран содержимого объекта класса точки:

// Класс точки

class Point

      {

            // Собственные элементы

            friend MPoint;    // Класс MPoint будет дружественным

      protected:

            // Защищённые элементы

            int x,y;                // Координаты

            int itype;        // Тип

            Point *next;   // Указатель на следующий элемент в списке

      public:

            // Общедоступные элементы

            Point(int a,int b):x(a), y(b), itype(0) {}     // Конструктор

            virtual void get()

                  {

                  // Вывод координат точки

                  cout << "Point(" << x << ‘,’ << y << ")n";

                  }

            virtual int type()      // Виртуальная функция возвращения типа

                  {

                  return itype;

                  }

      };

Класс отрезка определим как производный от класса точки, к которому добавлены координаты конца отрезка и переопределена функция вывода на экран:

// Класс линии (производный от класса точки)

class Line: public Point

      {

            // Собственные элементы

            friend MPoint;    // Класс MPoint будет дружественным

            int x2,y2;        // Координаты второго конца линии

            Point *next;      // Указатель на следующий элемент в списке

      public:

            // Общедоступные элементы

            // Конструктор

            Line(int a,int b,int a2,int b2):Point(a,b), x2(a2), y2(b2) {}

            virtual void get()

                  {

                  // Вывод координат линии

                  cout << "Line(" << x << ‘,’ << y << ")(";

                  cout << x2 << ‘,’ << y2 << ")n";

                  }

      } ;

Определим класс списка, состоящий из указателя на первый элемент и функций добавления точки, добавления отрезка и вывода элементов списка на экран:

// Класс списка

class MPoint

      {

              // Собственные элементы

            Point *p;         // Указатель на голову списка

      public:

            // Общедоступные элементы

            MPoint() { p = NULL; }       // Конструктор

            void insert(Point z);   // Добавление точки в список

            void insert(Line t);         // Добавление линии в список

            void display();              // Вывод содержимого списка

      };

Для того чтобы сделать доступными поля классов Point и Line, объявим класс Mpoint дружественным для этих классов. После добавления тестирующей главной программы получим окончательный текст программы.

#include <conio.h>

#include <iostream.h>

class MPoint;

// Класс точки

class Point

      {

            // Собственные элементы

            friend MPoint;    // Класс MPoint будет дружественным

      protected:

            // Защищённые элементы

            int x,y;                // Координаты

            int itype;        // Тип

            Point *next;   // Указатель на следующий элемент в списке

      public:

            // Общедоступные элементы

            Point(int a,int b):x(a), y(b), itype(0) {}     // Конструктор

            virtual void get()

                  {

                  // Вывод координат точки

                  cout << "Point(" << x << ‘,’ << y << ")n";

                  }

            virtual int type()      // Виртуальная функция возвращения типа

                  {

                  return itype;

                  }

      };

// Класс линии (производный от класса точки)

class Line: public Point

      {

            // Собственные элементы

            friend MPoint;    // Класс MPoint будет дружественным

            int x2,y2;        // Координаты второго конца линии

            Point *next;      // Указатель на следующий элемент в списке

      public:

            // Общедоступные элементы

            // Конструктор

            Line(int a,int b,int a2,int b2):Point(a,b), x2(a2), y2(b2) {}

            virtual void get()

                  {

                  // Вывод координат линии

                  cout << "Line(" << x << ‘,’ << y << ")(";

                  cout << x2 << ‘,’ << y2 << ")n";

                  }

      } ;

// Класс списка

class MPoint

      {

            // Собственные элементы

              Point *p;                      // Указатель на голову списка

      public:

            // Общедоступные элементы

            MPoint() { p = NULL; }       // Конструктор

            void insert(Point z);   // Добавление точки в список

            void insert(Line t);         // Добавление линии в список

            void display();              // Вывод содержимого списка

      };

// Вывод содержимого списка

void MPoint::display()

      {

      Point *q = p;     // Создаём указатель и устанавливаем его

                        // на голову списка

      while(q)    // Пока не дойдём до конца списка

            {

            q->get();   // Вывод элемента списка

            q=q->next;  // Переход к следующему элементу

            }

      }

// Добавление точки в список

void MPoint::insert(Point z)

      {

      if(!p) // Если список пустой

            {

            p = new Point(z.x, z.y);     // Создаём новый элемент

            p->next = NULL;              // Следующего элемента пока нет

            return;                      // Выход из функции

            }

      // Если список не пустой

      Point *q = p;     // Создаём указатель и устанавливаем его

                        // на голову списка

      // Идём до конца списка

      while(q->next)

            q = q->next;      // Переход к следующему элементу списка

      q->next = new Point(z.x,z.y);      // Создаём новый элемент

      q->next->next = NULL;              // Следующего элемента пока нет

      }

// Добавление линии в список

void MPoint::insert(Line z)

      {

      // Если список пустой

      if(!p)

            {

            p = new Line(z.x,z.y,z.x2,z.y2);   // Создаём новый элемент

            p->next = NULL;              // Следующего элемента пока нет

            return;                      // Выход из функции

            }

      // Если список не пустой

      Point *q = p;     // Создаём указатель и устанавливаем его

                        // на голову списка

      // Идём до конца списка

      while(q->next)

            q = q->next;      // Переход к следующему элементу списка

      q->next = new Line(z.x,z.y,z.x2,z.y2);   // Создаём новый элемент

      q->next->next = NULL;              // Следующего элемента пока нет

      }

void main()

      {

      clrscr();   // Очистка экрана

      MPoint a;   // Создаём список

      Line l1(10,100,-1,0);   // Создаём линию

  Point p1(1,2);              // Создаём точку

      a.insert(l1);           // Добавляем в список линию

      a.insert(l1);           // Добавляем в список линию

      a.insert(p1);           // Добавляем в список точку

      a.insert(p1);           // Добавляем в список точку

      a.insert(l1);           // Добавляем в список линию

      a.insert(p1);           // Добавляем в список точку

      a.display();            // Выводим содержимое списка на экран

      getch();          // Ожидание нажатия клавиши

      }

В результате работы программы на экран будут выведены строки:

      Line(10,100)(-1,0)

      Line(10,100)(-1,0)

      Point(1,2)

      Point(1,2)

      Line(10,100)(-1,0)

      Point(1,2)