Ключевое слово friend позволяет определенной функции или другому классу иметь доступ к приватным и защищенным членам класса, где friend объявлен. Friend-функции могут быть как глобальными, так и методами других классов. Такая конструкция дает возможность реализовать функции, которым требуется доступ к внутреннему состоянию класса, но которые логически не связаны с интерфейсом этого класса.
Рекомендуется использовать friend:
Внимание:
Пример:
class Box { int width; public: Box(int w): width(w) {} friend void printWidth(const Box &b); }; void printWidth(const Box &b) { std::cout << b.width << std::endl; }
Вопрос: Может ли friend-функция быть виртуальной?
Частый ответ: Да, ведь friend — это модификатор функции.
Правильный ответ: Нет, friend-функции не могут быть виртуальными, потому что они не являются членами класса!
Пример:
class Example { friend virtual void foo(); // Ошибка компиляции: virtual не применяется к friend };
История: При проектировании матричной библиотеки все арифметические операторы сделали friend-функциями для ускорения, но забыли про поддержку константности и избыточно открыли доступ к приватным членам. Позднее возникла проблема — в проекте другие функции нечаянно меняли внутреннее состояние Matrix.
История: В корпоративной системе классы-помощники стали friend друг другу для разделения доступа к приватным членам. Это привело к циклическим зависимостям — добавление новой фичи требовало изменения всех связанных классов. Последовавший рефакторинг занял недели.
История: Для закрытых тестов решили тестовый класс сделать friend к production классу. Когда появилось несколько наборов unit-тестов, отслеживать, какие приватные методы на самом деле используются, стало невозможно — тесты начали зависеть от внутренней реализации, что привело к сложному поддержанию кода.