Skip to the content.

Ключевое слово friend позволяет для класса определить дружественные функции, классы и методы.

Кстати, нет разницы какой модификатор у friend: public, protected, private работают одинаково.

Дружественные классы

struct String
{
  friend struct StringBuffer;
private:
    char * data_;
    size_t len_;
};

struct StringBuffer
{
    char * get_data_(String const & s)
    {
        return s.data_; // имеет доступ к private полям String
    }
};

Дружественные функции

Дружественные функции можно определять прямо внутри класса (потому что они станут inline).

struct String
{
  friend std::ostream & operator<<(std::ostream & os, String const & s)
  {
      os << s.data_;
  }
private:
    char * data_;
    size_t len_;
};

Дружественные методы

Есть некоторые сложности:

struct String; // необходимо объявить для StringBuffer::print_String

struct StringBuffer
{
    // можно только объявить, поскольку String еще не определён, мы не знаем какие у него есть поля
    void print_String(String const & s); 
};

struct String
{
friend void StringBuffer::print_String(String const & s);
private:
    char * data_;
    size_t len_;
};

void StringBuffer::print_String(String const & s) { std::cout << s.data_; }

Стоит понимать, что отношение наследования не задаёт отношение дружбы, это разные вещи: отношение дружбы сильнее чем отношение наследования (друг может использовать private поля, а наследник только protected).

Однако с friend тоже есть проблемы из-за которых его использование не желательно: