Инструменты пользователя

Инструменты сайта


examination:oop:question38

38. Дружественные функции: основные свойства, номенклатура. Ситуации, определяющие их необходимость и полезность. Наборы дружественных функций, дружественные классы. Объявление дружественной функции: синтаксис, размещение, семантика, требования к параметрам и типу возвращаемого значения.

Зачем это может понадобиться? Одна из причин может быть следующей, например - при доступе к внутренним переменным класса через его функции уменьшается эффективность работы за счет затрат на вызов функции. В большинстве случаев это не критично, но не всегда. В некоторых случаях это может играть существенную роль. Конечно, можно добавить новый метод к классу для получения прямого доступа к внутренним переменным. Однако, в большинстве случаев, интерфейс класса спланирован для выполнения определенного круга операций, и наша функция может оказаться как бы ни у дел. Или, еще один пример, нам необходимо получить прямой доступ к внутренним данным двух разных классов.

Спецификаторы доступа класса позволяют указывать, могут ли функции вне определенного вами класса обращаться к его элементам. Может, однако, случиться, что вам потребуется обеспечить определенной функции или классу доступ к элементам вашего класса, специфицированным как private или protected. Для обеспечения такой возможности используется ключевое слово friend. Вы можете разрешить элементам другого класса (anotherClass) полный доступ к элементам вашего класса (myClass), объявленным как private или protected, включив в определение вашего класса описание friend.

Например:

class myClass
{
  friend class anotherClass;
};

Аналогично вы можете разрешить обычной функции или функции-элементу другого класса полный доступ к элементам класса с помощью описания friend.

Например:

class myClass
{
  friend void anotherClass::MemberFuncName(int);
  friend void regularFuncName(double);
};

К друзьям и дружественности применимы следующие правила:

  • на описания friend не влияют спецификаторы public,
  • protected или private;
  • описания friend не взаимны: если А объявляет В другом, то это не означает, что А является другом для В;
  • дружественность не наследуется: если А объявляет В другом, классы, производные от В, не будут автоматически получать доступ к элементам А;
  • дружественность не является переходным свойством: если А объявляет В другом, классы, производные от А, не будут автоматически признавать дружественность В.

Обычное объявление функции-члена гарантирует три логически разные вещи:

  • во-первых, функция имеет право доступа к закрытой части объявления класса;
  • во-вторых, функция находится в области видимости класса;
  • в-третьих, функция должна вызываться для объекта класса, то есть имеется указатель this.

Объявив функцию-член как static, мы придаем ей только первые два свойства. Объявив функцию как friend, мы наделяем ее только первым свойством.

Так же как и функции-члены, функции-друзья явно указываются в объявлении класса, друзьями которого они являются. Поэтому они в той же мере являются частью интерфейса класса, в какой ею являются функции-члены. Так же как и объявление члена, объявление friend не добавляет новое имя в охватывающую область видимости.

Например:

class Matrix
{
friend class Xform;
friend Matrix invert (const Matrix&);};
Xform x; /* ошибка: в текущей области видимости нет имени Xform */
Matrix (*p)(const Matrix&) = &invert; /* ошибка: в текущей области видимости нет имени invert */
examination/oop/question38.txt · Последние изменения: 2014/01/15 12:22 (внешнее изменение)