Объектно-ориентированное программирование - Учебное пособие (А.А. Хусаинов)

2.7. дружественные классы

 

Напомним, что для того, чтобы функция, определенная обычным образом, получила доступ ко всем членам класса, включая закрытые, ее следует объявить дружественной, указав в теле класса ее прототип с ключевым словом friend. Функцией, дружественной классу, может быть как произвольная внешняя функция, так и составная функция другого класса, который должен быть уже определен. Например, если мы хотим перегрузить операцию вывода на экран элементов двумерного массива, определенного выше классом twomas, то нам будет нужен доступ к закрытым членам класса. Для обеспечения этого доступа в теле класса следует объявить прототип функции

 

friend ostream& operator << (ostream& o, twomas& d);

 

и определить операцию вывода с помощью внешней подпрограммы (функции):

 

ostream& operator << (ostream& o, twomas& d)

   {

   int i, j;

  

   for(i = 1; i <= d.n; i++)

               {

               for(j = 1; j <= d.n; j++)

                           o << d(i, j) << ‘ ‘;

               o << “ ”;

               }

 

   return o;

   }

 

Если класс содержит объекты другого класса в качестве полей, то его составным функциям необходим дополнительный доступ к закрытым членам этих полей. Например, в классе вектора, состоящего из n комплексных чисел

 

   class Vectorc

               {

                           Complex *z;

               Public:

                           double norma();

               };

составная функция norma(), возвращающая максимум абсолютных величин вещественных и мнимых компонент вектора, не имеет доступа к этим компонентам. Чтобы обеспечить этот доступ, в классе Complex следует указать функцию Vectorc::norma() как   дружественную.  Поскольку  к   моменту  объявления   составной   функции   класс

Vectorc должен быть определен, то следует указать перед определением класса        Complex этот класс Vectorc как внешний (глобальный):

 

   class Vectorc;

 

   class Complex

               {

               double Re, Im;

               friend double Vectorc::norma();

               …

               };

 

а затем определить класс Vectorc.

Существует возможность сделать доступными все члены класса А для каждой  из составных функций класса В. Для реализации этой возможности достаточно класс B объявить дружественным для класса А. К моменту объявления класс B должен быть определен или объявлен как внешний. Члены класса А не становятся доступными для дружественных функций класса B.

Пример. Определим класс графического окна, в которое будет выводиться график линейной функции. Линейная функция определяется как класс.

 

#include <graphics.h>

#include <conio.h>

 

class Wnd;    // Прототип класса Wnd

 

// Класс - функция

class Func

   {

   // Закрытые элементы

               double k, b; // y = kx + b

               friend class Wnd;        // Объявление дружественного класса

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

               Func(double k1, double b1=0): k(k1), b(b1) {}         // Конструктор

   };

 

// Класс окна

class Wnd

   {

   // Закрытые элементы

               int xleft, xright, ytop, ybot; // Реальные координаты окна

               double xmin, ymin, xmax, ymax; // Относительные координаты окна

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

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

               Wnd(double x0, double y0, double x1, double y1,

                           int xl=0, int yt=0, int xr=639, int yb=479):

                           xmin(x0), ymin(y0), xmax(x1), ymax(y1),

                           xleft(xl), ytop(yt), xright(xr), ybot(yb) {}

 

               Wnd& operator << (Func);     // Перегрузка операции <<

   };

 

// Перегрузка операции <<

Wnd& Wnd::operator << (Func f)

   {

   double xkof, ykof;      // Коэффициенты перевода относительных

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

   xkof = (xright-xleft)/(xmax-xmin);

   ykof = (ybot-ytop)/(ymax-ymin);

   rectangle(xleft, ytop, xright, ybot);     // Рамка

 

   line(xleft,

               ytop+(ymax-ymin)*ykof/2,

               xright,

               ytop+(ymax-ymin)*ykof/2);   // Ось х

 

   line(xleft+(xmax-xmin)*xkof/2,

               ytop,

               xleft+(xmax-xmin)*xkof/2,

               ybot);                                       // Ось у

 

   line((xright - xleft)/2 + xmin*xkof,

               (ybot - ytop)/2 - (xmin*f.k+f.b)*ykof,

               (xright - xleft)/2 + xmax*xkof,

               (ybot - ytop)/2 - (xmax*f.k+f.b)*ykof);         // Вывод функции

 

   return (*this);

   }

 

void main()

   {

   int gd=DETECT, gm;

 

   Wnd w(-5, -3, 5, 3);    // Определение окна

   Func phi(1, 1);             // Определение функции

 

   initgraph(&gd, &gm, "");        // Инициализация графики

 

   w<<phi;           // Вывод функции phi в окно w

 

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

   closegraph();    // Закрытие графики

   }

 

Результаты работы программы