← Назад к вопросам

Что такое 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;
};