На этом шаге мы рассмотрим организацию дружественных классов.
Класс может быть дружественным другому классу. Это означает, что все компонентные функции класса являются дружественными для другого класса. Дружественный класс должен быть определен вне тела класса, "предоставляющего дружбу". Например, так:
class X2 { friend class X1; ... }; class X1 { ... // Определение дружественного класса. void f1(...); void f2(...); . . . . };
В данном примере функции f1 и f2 из класса X1 являются друзьями класса Х2, хотя они описываются без спецификатора friend.
Все компоненты класса доступны в дружественном классе. Дружественный класс может быть определен позже (ниже), нежели описан как дружественный.
В качестве примера "дружбы" между классами рассмотрим класс pointN - "точка в N-мерном пространстве" и дружественный ему класс vectorN - "радиус-вектор точки" ("вектор с началом в начале координат N-мерного пространства"). Все компоненты точки - ее размерность Npoint и массив координат х[Npoint] - собственные, и доступ к ним в классе vectorN возможен только за счет дружеских отношений. Конструктор класса pointN выделяет память для массива координат и инициализирует этот массив заданным значением параметра double d;. Конструктор класса vectorN формирует объект "радиус-вектор" или просто "вектор" по двум объектам класса pointN, проверяя равенство их размерностей. Объекты класса pointN задают начало и конец вектора, который затем приводится к началу координат. Кроме конструктора в классе vectorN введена функция для определения нормы вектора, которая вычисляется как сумма квадратов координат его конца. В основной программе сформирован вектор по двум точкам 2-мерного пространства, затем сделана неправильная попытка создать вектор из двух точек разной размерности. Текст программы:
//OOР15_1.СРР - дружественные классы. #include <iostream.h> #include <stdlib.h> // Для функции exit(). // Класс "точка в N-мерном пространстве": class pointN { int Npoint; // Размерность пространства. double *x; // Указатель на массив координат точки. // Описание дружественного класса: friend class vectorN; public: pointN(int n, double d = 0.0); // Конструктор "точек". }; // Определение конструктора: pointN::pointN(int n, double d) { Npoint = n; // Определение размерности. // Выделение памяти для координат: x = new double [Npoint]; for (int i = 0; i < Npoint; i++) x[i] = d; // Инициализация массива координат. } // Класс "радиус-вектор": class vectorN { // Указатель на массив координат конца вектора: double *xv; int Nvector; // Размерность пространства. public: vectorN(pointN,pointN); // Конструктор "векторов". double norm(); // Норма вектора. }; // Определение конструктора: vectorN:: vectorN (pointN beg,pointN end) { if (beg.Npoint != end.Npoint) // Проверка точек. { cerr << "\nОшибка в размерностях точек!"; exit(1); // Завершение программы. } Nvector = beg.Npoint; // Размерность вектора. xv = new double [Nvector]; for (int i = 0; i < Nvector; i++) xv[i] = end.x[i] - beg.x[i]; // Определение координат. } double vectorN::norm() // Вычисление нормы вектора. { double dd = 0.0; for (int i = 0; i < Nvector; i++) dd += xv[i] * xv[i]; return dd; } void main(void) { pointN A(2,4.0); pointN B(2,2.0) ; vectorN V(A,B); cout << "\nНорма вектора: " << V.norm(); pointN X(3,2.0); vectorN Z(A,X); }
Результат выполнения программы:
Норма вектора: 8 Ошибка в размерностях точек!
Обратите внимание, что за счет дружественного отношения между классами конструктор класса vectorN напрямую с помощью уточненных имен обращается к компонентам класса pointN.
На следующем шаге мы начнем знакомиться с перегрузкой операций.