
-
Дружественные функции
Как уже было сказано ранее данные класса должны быть защищены от внешнего воздействия, то есть доступ к ним можно получить только с помощью функций-членов данного класса.
Тем не менее, как показывает практика, иногда необходимо получить прямой доступ к полям класса, не используя его интерфейс. Зачем это может понадобиться? Одна из причин может быть следующей: при доступе к внутренним переменным класса через его функции уменьшается эффективность работы за счет затрат на вызов функции. В большинстве случаев это не критично, но не всегда. Иногда это может играть существенную роль. Или, еще один пример, нам необходимо получить прямой доступ к внутренним данным двух разных классов.
Для решения подобного круга задач в С++ и существует возможность описания функции, функции-члена другого класса как дружественной (friend). Класс может предоставлять особые привилегии определенным внешним функциям или функциям-членам другого класса. Рассмотрим как работает этот механизм.
Для описания функции дружественной тому или иному классу, необходимо в описании этого класса объявить дружественную функцию, используя ключевое слово friend. Причем, обратите внимание, не играет никакой роли в каком из разделов класса разместить объявление дружественной функции.
class СPlayer
{
…
friend int F(const CPlayer &player)
}
Рисунок 17 - Объявление дружественной функции
Если обычные функции-члены имеют автоматический доступ ко всем данным своего класса за счет передачи скрытого параметра - указателя this на экземпляр класса, то дружественные функции требуют явной спецификации этого параметра. Действительно, объявленная в классе СPlayer дружественная функция F не принадлежит этому классу, а, значит, не может быть вызвана операторами player.F(), где player - экземпляр класса CPlayer. Синтаксически корректными будут обращения F (& player).
Опишем функцию, дружественную для классов CPlayer и CCircle. Пусть она возвращает истину, если объекты соответсвующих классов пересекаются и ложь – в противном случае. Функция будет иметь следующий вид:
int intersect(CPlayer &p, CCircle &o)
{
return fabs(o.x-p.x) < 20 && fabs(o.y-p.y) < 20;
}
Рисунок 18 – Реализация функции, дружественной для классов CPlayer и CCircle
Для того, чтобы данная функция могла получить доступ к закрытым полям классов CPlayer и CCircle, необходимо в описании этих классов добавить прототип данной функции с ключевым словом friend
class СPlayer
{
…
friend int intersect(CPlayer &, CCircle &);
}
class СCircle
{
…
friend int intersect(CPlayer &, CCircle &);
}
Рисунок 19 – Описание функции, дружественной для классов CPlayer и CCircle