Бьерн Страуструп - Язык программирования С++. Главы 5-8
Страница 13. Друзья



5.4.1 Друзья

 Пусть определены два класса: vector (вектор) и matrix (матрица).
 Каждый из них скрывает свое представление, но дает полный набор операций
 для работы с объектами его типа. Допустим, надо определить функцию,
 умножающую матрицу на вектор. Для простоты предположим, что
 вектор имеет четыре элемента с индексами от 0 до 3, а в матрице
 четыре вектора тоже с индексами от 0 до 3. Доступ к элементам
 вектора обеспечивается функцией elem(), и аналогичная функция есть
 для матрицы. Можно определить глобальную функцию multiply
 (умножить) следующим образом:

           vector multiply(const matrix& m, const vector& v);
           {
             vector r;
             for (int i = 0; i<3; i++) { // r[i] = m[i] * v;
                 r.elem(i) = 0;
                 for (int j = 0; j<3; j++)
                     r.elem(i) +=m.elem(i,j) * v.elem(j);
             }
             return r;
           }

 Это вполне естественное решение, но оно может оказаться очень
 неэффективным. При каждом вызове multiply() функция elem() будет
 вызываться 4*(1+4*3) раз. Если в elem() проводится настоящий
 контроль границ массива, то на такой контроль будет потрачено
 значительно больше времени, чем на выполнение самой функции, и в
 результате она окажется непригодной для пользователей. С другой
 стороны, если elem() есть некий специальный вариант доступа без
 контроля, то тем самым мы засоряем интерфейс с вектором и матрицей
 особой функцией доступа, которая нужна только для обхода контроля.
     Если можно было бы сделать multiply членом обоих классов
 vector и matrix, мы могли бы обойтись без контроля индекса при
 обращении к элементу матрицы, но в то же время не вводить специальной
 функции elem(). Однако, функция не может быть членом двух классов.
 Надо иметь в языке возможность предоставлять функции, не являющейся
 членом, право доступа к частным членам класса. Функция - не член
 класса, - имеющая доступ к его закрытой части, называется другом
 этого класса. Функция может стать другом класса, если в его
 описании она описана как friend (друг). Например:

            class matrix;

            class vector {
              float v[4];
              // ...
              friend vector multiply(const matrix&, const vector&);
            };

            class matrix {
              vector v[4];
              // ...
              friend vector multiply(const matrix&, const vector&);
            };

 Функция-друг не имеет никаких особенностей, за исключением права
 доступа к закрытой части класса. В частности, в такой функции
 нельзя использовать указатель this, если только она действительно
 не является членом класса. Описание friend является настоящим
 описанием. Оно вводит имя функции в область видимости класса,
 в котором она была описана, и при этом происходят обычные проверки
 на наличие других описаний такого же имени в этой области
 видимости. Описание friend может находится как в общей, так и в
 частной частях класса, это не имеет значения.
      Теперь можно написать функцию multiply, используя элементы
 вектора и матрицы непосредственно:

           vector multiply(const matrix& m, const vector& v)
           {
             vector r;
             for (int i = 0; i<3; i++) {  // r[i] = m[i] * v;
                 r.v[i] = 0;
                 for ( int j = 0; j<3; j++)
                     r.v[i] +=m.v[i][j] * v.v[j];
             }
             return r;
           }

      Отметим, что подобно функции-члену дружественная функция
 явно описывается в описании класса, с которым дружит. Поэтому она
 является неотъемлемой частью интерфейса класса наравне с
 функцией-членом.
      Функция-член одного класса может быть другом другого класса:

      class x {
         // ...
         void f();
      };

      class y {
         // ...
         friend void x::f();
      };

 Вполне возможно, что все функции одного класса являются друзьями
 другого класса. Для этого есть краткая форма записи:

        class x {
          friend class y;
          // ...
        };

 В результате такого описания все функции-члены y становятся друзьями
 класса x.

 
« Предыдущая статья   Следующая статья »