На этом шаге мы начнем изучение дружественных функций и их возможностей.
Дружественной функцией класса называется функция, которая, не являясь его компонентом, имеет доступ к его защищенным и собственным компонентам. Функция не может стать другом класса "без его согласия". Для получения прав друга функция должна быть описана в теле класса со спецификатором friend. Именно при наличии такого описания класс предоставляет функции права доступа к защищенным и собственным компонентам. Пример класса с дружественной функцией:
//OOР13_01.СРР - класс с дружественной функцией. #include <conio.h> // Для консольных функций в текстовом режиме. // Класс - "символ в заданной позиции экрана": class charlocus { int x, y; // Координаты знакоместа на экране дисплея. // Значение символа, связанного со знакоместом: char cc; // Прототип дружественной функции для замены символа: friend void friend_put(charlocus *, char); public: charlocus(int xi, int yi, char ci) // Конструктор. { x = xi; y = yi; cc = ci; } void display (void) // Вывести символ на экран. { gotoxy(x,y); putch(cc); } }; // Дружественная функция замены символа в конкретном // объекте: void friend_put(charlocus *p, char c) { p->cc = c; } void main (void) { charlocus D(20,4,'d'); // Создать объект. charlocus S(10,10,'s'); // Создать объект. D.display (); getch(); S.display (); getch(); friend_put(&D,'*'); D.display(); getch(); friend_put(&S,'#'); S.display(); getch(); }
Программа последовательно выводит на экран d (в позицию 20, 4), s (в позицию 10, 10), * (в позицию 20, 4), # (в позицию 10, 10).
Для работы с экраном в текстовом режиме использованы две функции из библиотеки Turbo С. Их прототипы находятся в заголовочном файле conio.h, где специфицированы так называемые "консольные" функции ввода-вывода. В других компиляторах языка C++ эти функции могут быть определены иначе.
Прокомментируем приведенную программу.
Функция friend_put() описана в классе charlocus как дружественная и определена как обычная глобальная функция (вне класса, без указания его имени, без операции :: и без спецификатора friend). Как дружественная она получает доступ к собственным данным класса и изменяет значение символа того объекта, адрес которого будет передан ей как значение первого параметра.
Выполнение основной программы очевидно. Создаются два объекта D и S, для которых определяются координаты мест на экране и символы (d, s). Затем общедоступная функция класса charlocus::display() выводит символы в указанные позиции экрана. Функция friend_put заменяет символы объектов, что демонстрирует повторный вывод на экран.
Отметим особенности дружественных функций.
имя_объекта.имя_функции и указатель_на_объект -> имя_функции
Итак, дружественная функция:
class CL { friend int f1 (...); ... }; int f1(...) { тело_функции }
class CLASS { ... char f2(...); ... }; class CL { ... friend char CLASS::f2(...); ... };
В примере класс CLASS с помощью своей компонентной функции f2() получает доступ к компонентам класса CL. Компонентная функция некоторого класса (CLASS) может быть объявлена дружественной функцией другому классу (CL), если только определение этого первого класса размещено раньше, чем определение второго.
// Предварительное неполное определение класса. class CL2; class CL1 { friend void ff(CL1,CL2); ... }; class CL2 { friend void ff(CL1,CL2); ... }; void ff(CL1 cl, CL2 c2) { тело_функции }
На следующем шаге мы продолжим знакомство с друзьями классов, в частности, рассмотрим примеры использования дружественных функций.