Дружественные функции в C++ — это функции, имеющие доступ к закрытым (private) и защищённым (protected) членам класса. Это позволяет обходить ограничения модификаторов доступа, обеспечивая гибкость в работе с классами. Рассмотрим практический пример.
Пример: Классы Person и Car
Создадим два класса: Person, описывающий человека, и Car, описывающий машину. Сначала реализуем их без дружественных функций.
class Car {
private:
std::string name; // Название машины
public:
void InfoCar() {} // Метод вывода информации о машине
};
class Person {
private:
int age; // Возраст
std::string name; // Имя
public:
void InfoCar() {} // Метод вывода информации о машине
};
Теперь создадим функцию, выводящую информацию о владельце машины: «Человек с именем [имя владельца] имеет машину [имя машины]». Попробуем реализовать её без дружественных функций:
void InfoCar(const Car& car, const Person& person) {
std::cout << "Человек с именем " << person.name << " имеет машину " << car.name << std::endl;
}
Эта функция не скомпилируется, так как name в обоих классах — закрытый член. Доступ к нему напрямую через объекты классов невозможен.
Решение с дружественными функциями
Решим проблему, используя дружественные функции. Создадим функцию InfoCar, объявленную как дружественная для обоих классов:
class Car {
private:
std::string name;
public:
Car(const std::string& carName) : name(carName) {}
friend void InfoCar(const Car& car, const Person& person);
};
class Person {
private:
int age;
std::string name;
public:
Person(const std::string& personName) : name(personName) {}
friend void InfoCar(const Car& car, const Person& person);
};
void InfoCar(const Car& car, const Person& person) {
std::cout << "Человек с именем " << person.name << " имеет машину " << car.name << std::endl;
}
Ключевое слово friend перед объявлением функции InfoCar в каждом классе указывает компилятору, что функция дружественна для данного класса и имеет доступ к его закрытым членам. Параметры функции принимаются по константной ссылке (const &), что повышает эффективность передачи больших объектов.
Для корректной компиляции необходимо объявить прототип класса Car перед объявлением класса Person, чтобы избежать ошибки, связанной с неизвестным типом Car в объявлении дружественной функции в классе Person.
Проверка работы кода
Проверим работоспособность кода, создав объекты и вызвав функцию InfoCar:
int main() {
Car bmw("BMW");
Person john("John");
InfoCar(bmw, john); // Выведет: Человек с именем John имеет машину BMW
return 0;
}
Программа скомпилируется и выполнится, выведя ожидаемый результат. Благодаря дружественным функциям, удалось обойти ограничения модификаторов доступа и реализовать необходимую функциональность.
Дружественные функции — мощный механизм доступа к закрытым членам классов извне, но использовать их следует осторожно. Переизбыток дружественных функций может снизить инкапсуляцию и затруднить сопровождение кода. Внимательно оценивайте необходимость их использования в каждом конкретном случае.