На этом шаге мы начнем изучение дружественных функций и их возможностей.
Дружественной функцией класса называется функция, которая, не являясь
его компонентом, имеет доступ к его защищенным и собственным компонентам.
Функция не может стать другом класса "без его согласия". Для получения прав друга
функция должна быть описана в теле класса со спецификатором 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++ эти функции могут
быть определены иначе.
- void gotoxy (int х, int у) - позволяет поместить курсор в позицию экрана с
"координатами" х (по горизонтали) и у (по вертикали). В обычном (текстовом) режиме количество
строк 25 (у меняется от 0 до 24), количество столбцов 80 (х меняется от 0 до 79). Позиция
с координатами (0,0) соответствует левому верхнему углу экрана. - void putch (int s) - выводит на экран в местоположение курсора изображение символа,
код которого определяется значением параметра s. - int getch(void) - также относится к библиотечным консольным функциям. Ее основное назначение -
чтение кода из буфера клавиатуры без вывода соответствующего символа на экран. При
вызове этой функции программа останавливает выполнение и ожидает сигнала от клавиатуры.
Тем самым у пользователя появляется возможность проследить смену изображений на экране.
Прокомментируем приведенную программу.
Функция friend_put() описана в классе charlocus как дружественная и определена
как обычная глобальная функция (вне класса, без указания его имени, без операции :: и без
спецификатора friend). Как дружественная она получает доступ к собственным данным
класса и изменяет значение символа того объекта, адрес которого будет передан ей как
значение первого параметра.
Выполнение основной программы очевидно. Создаются два объекта D и S, для
которых определяются координаты мест на экране и символы (d, s). Затем общедоступная функция
класса charlocus::display() выводит символы в указанные позиции экрана. Функция friend_put заменяет
символы объектов, что демонстрирует повторный вывод на экран.
Отметим особенности дружественных функций.
передаваться дружественной функции только явно через аппарат параметров.
имя_объекта.имя_функции и указатель_на_объект -> имя_функции
Все это связано с тем фактом, что дружественная функция не является компонентом класса.
(public, protected, private). Место размещения прототипа дружественной функции внутри
определения класса безразлично. Права доступа дружественной функции не изменяются и
не зависят от спецификаторов доступа. В приведенном примере описание функции
friend_put() помещено в разделе, который по умолчанию имеет статус доступа private.
Итак, дружественная функция:
- не может быть компонентной функцией того класса, по отношению к которому определяется как
дружественная; - может быть глобальной функцией:
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) { тело_функции }
На следующем шаге мы продолжим знакомство с друзьями классов, в частности,
рассмотрим примеры использования дружественных функций.