← Назад к вопросам
Что такое friend function в C++?
1.0 Junior🔥 111 комментариев
#ООП и проектирование#Структуры данных и алгоритмы#Язык C++
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое friend function в C++?
Friend function (дружественная функция) — это функция, которая не является членом класса, но имеет доступ к приватным и защищённым членам класса. Дружественные функции нарушают инкапсуляцию, поэтому их следует использовать с осторожностью.
Основные характеристики
1. Объявление:
- Объявляется внутри класса с ключевым словом
friend - Определяется вне класса как обычная функция
- Не является членом класса (нет доступа к
this)
2. Доступ:
- Может обращаться к приватным (private) членам
- Может обращаться к защищённым (protected) членам
- Нарушает инкапсуляцию класса
3. Наследование:
- НЕ наследуется — дружественность не передаётся подклассам
- Друг базового класса не друг производного класса
Пример с friend функцией
#include <iostream>
class MyClass {
private:
int value;
public:
MyClass(int v) : value(v) {}
// Объявляем дружественную функцию
friend void printValue(const MyClass& obj);
friend void modifyValue(MyClass& obj, int newValue);
};
// Определение дружественной функции (вне класса)
void printValue(const MyClass& obj) {
// Может обращаться к приватному члену
std::cout << "Value: " << obj.value << std::endl;
}
void modifyValue(MyClass& obj, int newValue) {
// Может изменять приватные члены
obj.value = newValue;
std::cout << "Value changed to: " << obj.value << std::endl;
}
int main() {
MyClass obj(42);
printValue(obj); // Value: 42
modifyValue(obj, 100); // Value changed to: 100
printValue(obj); // Value: 100
return 0;
}
Friend класс
Весь класс может быть другом другого класса:
class Engine;
class Car {
private:
int speed;
Engine* engine;
public:
Car() : speed(0) {}
// Весь класс Engine — друг Car
friend class Engine;
};
class Engine {
public:
void accelerate(Car& car) {
car.speed += 10; // Доступ к приватному члену Car
std::cout << "Speed: " << car.speed << std::endl;
}
};
int main() {
Car car;
Engine engine;
engine.accelerate(car); // Speed: 10
engine.accelerate(car); // Speed: 20
return 0;
}
Операторы как friend функции
Часто дружественные функции используются для перегрузки операторов:
#include <iostream>
class Complex {
private:
double real;
double imag;
public:
Complex(double r = 0, double i = 0) : real(r), imag(i) {}
// Дружественная функция для оператора +
friend Complex operator+(const Complex& a, const Complex& b);
// Дружественная функция для оператора <<
friend std::ostream& operator<<(std::ostream& os, const Complex& c);
};
// Перегрузка оператора +
Complex operator+(const Complex& a, const Complex& b) {
return Complex(a.real + b.real, a.imag + b.imag);
}
// Перегрузка оператора <<
std::ostream& operator<<(std::ostream& os, const Complex& c) {
os << c.real << " + " << c.imag << "i";
return os;
}
int main() {
Complex c1(3, 4);
Complex c2(1, 2);
Complex c3 = c1 + c2;
std::cout << c1 << std::endl; // 3 + 4i
std::cout << c2 << std::endl; // 1 + 2i
std::cout << c3 << std::endl; // 4 + 6i
return 0;
}
Шаблонные friend функции
template<typename T>
class Container {
private:
T value;
public:
Container(T v) : value(v) {}
// Шаблонная дружественная функция
template<typename U>
friend void printContainer(const Container<U>& c);
};
template<typename T>
void printContainer(const Container<T>& c) {
std::cout << "Value: " << c.value << std::endl;
}
int main() {
Container<int> intContainer(42);
Container<double> doubleContainer(3.14);
printContainer(intContainer); // Value: 42
printContainer(doubleContainer); // Value: 3.14
return 0;
}
Friend и наследование
class Base {
private:
int baseValue = 10;
public:
friend void showBase(const Base& b);
};
void showBase(const Base& b) {
std::cout << "Base value: " << b.baseValue << std::endl;
}
class Derived : public Base {
private:
int derivedValue = 20;
};
int main() {
Base base;
Derived derived;
showBase(base); // Base value: 10
// showBase(derived); // ОШИБКА! дружественность не наследуется
// Но это работает, т.к. Derived наследуется от Base
showBase(static_cast<Base&>(derived)); // Base value: 10
return 0;
}
Плюсы и минусы friend функций
| Аспект | Комментарий |
|---|---|
| Удобство | Просто предоставить доступ к приватным членам |
| Гибкость | Позволяет реализовать некоторые паттерны |
| Инкапсуляция | Нарушает инкапсуляцию |
| Тесная связь | Создаёт зависимость между классом и функцией |
| Поддерживаемость | Сложнее отследить зависимости |
Когда использовать friend функции
1. Перегрузка операторов:
class Vector {
friend Vector operator*(double scalar, const Vector& v);
friend std::ostream& operator<<(std::ostream& os, const Vector& v);
};
2. Очень тесное взаимодействие между двумя классами:
class Matrix;
class Vector {
friend class Matrix;
};
3. Когда функция логически принадлежит классу, но не должна быть его методом:
class Complex {
friend Complex abs(const Complex& c); // Величина комплексного числа
};
Когда НЕ использовать friend функции
- Для простого доступа — лучше использовать getter/setter
- Для расширения функционала — лучше наследование
- Если это создаёт циклическую зависимость — переорганизовать код
- Для скрытия сложности — переорганизовать архитектуру
Альтернативы friend функциям
1. Public getter/setter:
class MyClass {
private:
int value;
public:
int getValue() const { return value; }
void setValue(int v) { value = v; }
};
2. Вспомогательные функции-члены (protected):
class MyClass {
protected:
void helperFunction() { /* ... */ }
};
3. Паттерн Pimpl (Pointer to Implementation):
class Interface {
private:
std::unique_ptr<Implementation> impl;
};