Язык программирования C++. Вводный курс

Друзья


Иногда удобно разрешить некоторым функциям доступ к закрытым членам класса. Механизм друзей

позволяет классу разрешать доступ к своим неоткрытым членам.

Объявление друга начинается с ключевого слова friend и может встречаться только внутри определения класса. Так как друзья не являются членами класса, то не имеет значения, в какой секции они объявлены. В примере ниже мы сгруппировали все подобные объявления сразу после заголовка класса:

class Screen {

   friend istream&

      operator>>( istream&, Screen& );

   friend ostream&

      operator<<( ostream&, const Screen& );

public:

   // ... оставшаяся часть класса Screen



};

Операторы ввода и вывода теперь могут напрямую обращаться к закрытым членам класса Screen. Простая реализация оператора вывода выглядит следующим образом:

#include <iostream>

ostream& operator<<( ostream& os, const Screen& s )

{

   // правильно: можно обращаться к _height, _width и _screen

   os << "<" << s._height

      << "," << s._width << ">";

   os << s._screen;

   return os;

}

Другом может быть функция из пространства имен, функция-член другого класса или даже целый класс. В последнем случае всем его функциям-членам предоставляется доступ к неоткрытым членам класса, объявляющего дружественные отношения. (В разделе 15.2 друзья обсуждаются более подробно.)


Рассмотрим еще раз перегруженные операторы равенства для класса String, определенные в области видимости пространства имен. Оператор равенства для двух объектов String

выглядит следующим образом:

bool operator==( const String &str1, const String &str2 )

{

   if ( str1.size() != str2.size() )

      return false;

   return strcmp( str1.c_str(), str2.c_str() ) ? false : true;

}

Сравните это определение с определением того же оператора как функции-члена:

bool String::operator==( const String &rhs ) const

{

   if ( _size != rhs._size )

      return false;

   return strcmp( _string, rhs._string ) ? false : true;

}

Нам пришлось модифицировать способ обращения к закрытым членам класса String. Поскольку новый оператор равенства– это глобальная функция, а не функция-член, у него нет доступа к закрытым членам класса String. Для получения размера объекта String и лежащей в его основе C-строки символов используются функции-члены size() и c_str().

Альтернативной реализацией является объявление глобальных операторов равенства друзьями класса String. Если функция или оператор объявлены таким образом, им предоставляется доступ к неоткрытым членам.

Объявление друга (оно начинается с ключевого слова friend) встречается только внутри определения класса. Поскольку друзья не являются членами класса, объявляющего дружественные отношения, то безразлично, в какой из секций – public, private или protected – они объявлены. В примере ниже мы решили поместить все подобные объявления сразу после заголовка класса:

class String {

   friend bool operator==( const String &, const String & );

   friend bool operator==( const char *, const String & );

   friend bool operator==( const String &, const char * );

public:

   // ... остальная часть класса String

};

В этих трех строчках три перегруженных оператора сравнения, принадлежащие  глобальной области видимости, объявляются друзьями класса String, а следовательно, в их определениях можно напрямую обращаться к закрытым членам данного класса:



Содержание раздела