Друзья в C++ — это способ нарушить инкапсуляцию, которую обеспечивают классы. Если использовать аналогию из реальной жизни, друзья похожи на надежных знакомых, которым предоставляется доступ к вашей личной информации, в отличие от незнакомцев.

Рассмотрим простой пример…

Возьмите следующее определение класса с именем MyClass.

class MyClass {
  int value;
public:
  MyClass(int value) : value(value) {}
};

Если бы мы попытались написать глобальную функцию отображения для объектов этого класса, мы бы сделали что-то вроде следующего.

// INCORRECT : Will Cause Compilation Failure
void display(MyClass& myClass) {
  // ERROR: myClass.value is private in MyClass!
  std :: cout << myClass.value << std :: endl; 
}

Но, как мы знаем, компиляция этой функции завершится ошибкой, потому что она пытается получить доступ к закрытым членам класса MyClass, а поскольку функция display не является членом, она не может этого сделать.

Можем ли мы заставить нашу функцию отображения работать? Давайте попробуем найти решение…

Подход 1. Почему бы не пометить член личных данных как value общедоступный? Таким образом, метод display может легко получить доступ к этому члену данных.

Проблема с подходом 1.Пометка value как общедоступная ослабит инкапсуляцию не только для метода display, но и для всех остальных методов. Это не лучший подход и может привести к плохому дизайну.

Подход 2. Итак, если мы не можем пометить член данных value как общедоступный, почему бы не сделать метод display членом MyClass?

Проблема с подходом 2. Фактическая реализация метода отображения зависит от варианта использования, и может быть невозможно охватить все различные реализации в самом определении класса. Лучше оставить реализацию метода display самому пользователю.

Ни один из стандартных подходов не подходит для нашего варианта использования. Следующий вопрос, который мы должны себе задать: «Есть ли способ выборочно нарушить инкапсуляцию только для метода отображения?». Удивительно, но ответ — большое ДА.

Как всегда… Друзья спешат на помощь

Класс в C++ может помечать другие функции и классы как друзей. Затем эти функции и классы могут получить доступ к закрытым (наряду с общедоступными) членам класса, где они помечены как друзья. Вот так мы выборочно ослабляем инкапсуляцию.

Таким образом, чтобы наш пример заработал, мы можем пометить глобальную функцию отображения как друга класса MyClass. Вот обновленное определение класса.

class MyClass {
  int value;
public:
  MyClass(int value) : value(value) {}
  friend void display(MyClass& myClass); // display method marked friend
};

Благодаря этому небольшому изменению метод отображения теперь может обращаться к закрытым членам класса MyClass. Разве это не гладко? 🤯

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

Функции друга

Дружественная функция для класса имеет следующие свойства:

  • Он имеет доступ к закрытым и защищенным членам класса.
  • Должен иметь свой прототип, включенный в область класса с ключевым словом friend.
  • Он не вызывается с вызывающим объектом класса.
  • Функция друга может быть объявлена ​​дружественной в нескольких классах.

Также функция друга может быть —

  • Любая глобальная функция
  • Функция-член другого класса
  • Шаблон функции

Классы друзей

Друг класса класса —

  • имеет доступ к закрытым и защищенным членам класса в дополнение к открытым членам
  • не имеет своего имени, квалифицированного с областью класса
  • может быть объявлен другом более чем в одном классе

Кроме того, класс друзей может быть —

  • Класс
  • Шаблон класса

Мы используем следующий синтаксис, чтобы пометить другой класс (скажем, OtherClass) как друга в нашем классе.

class MyClass {
  ...
  friend class OtherClass;
  ...
};

Свойства друга(корабль)

Ниже приведены некоторые свойства друга в C++:

Дружба не является ни коммутативной, ни транзитивной.

[Коммутативность] A является другом B, не означает, что B является другом A.

[Транзитивность] Кроме того, то, что A является другом B, а B является другом C, не означает, что A является другом C.

На этом мы подошли к концу еще одной статьи о C++. Поздравляю с завершением, надеюсь, вы сегодня узнали что-то новое.

Если вы хотите продолжить чтение, вы можете проверить следующие похожие блоги -

  1. Копирование в C++
  2. Спецификаторы доступа в C++
  3. Константные переменные в C++
  4. Классы в C++
  5. Статические члены в C++

Вы также можете ознакомиться с полной серией здесь.

Наконец, если вам понравилась моя работа, выразите свою признательность, похлопав в ладоши. Вы также можете подписаться на мою рассылку, чтобы не пропустить следующие статьи.