Поиск…


Вступление

Хорошо продуманные классы инкапсулируют их функциональность, скрывая их реализацию, обеспечивая при этом чистый документированный интерфейс. Это позволяет перепроектировать или изменить, если интерфейс не изменился.

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

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

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

// Forward declaration of functions.
void friend_function();
void non_friend_function();

class PrivateHolder {
public:
    PrivateHolder(int val) : private_value(val) {}
private:
    int private_value;
    // Declare one of the function as a friend.
    friend void friend_function();
};

void non_friend_function() {
    PrivateHolder ph(10);
    // Compilation error: private_value is private.
    std::cout << ph.private_value << std::endl;
}

void friend_function() {
    // OK: friends may access private values.
    PrivateHolder ph(10);
    std::cout << ph.private_value << std::endl;
}

Модификаторы доступа не изменяют семантику друзей. Публичные, защищенные и частные объявления друга эквивалентны.

Объявления друзей не наследуются. Например, если мы подклассифицируем PrivateHolder :

class PrivateHolderDerived : public PrivateHolder {
public:
    PrivateHolderDerived(int val) : PrivateHolder(val) {}
private:
    int derived_private_value = 0;
};

и попытайтесь получить доступ к его членам, мы получим следующее:

void friend_function() {
    PrivateHolderDerived pd(20);
    // OK.
    std::cout << pd.private_value << std::endl;
    // Compilation error: derived_private_value is private.
    std::cout << pd.derived_private_value << std::endl;
}

Обратите внимание, что PrivateHolderDerived члена PrivateHolderDerived не может получить доступ к PrivateHolder::private_value , в то время как функция друга может это сделать.

Метод Friend

Методы могут объявляться как друзья, так и функции:

class Accesser {
public:
    void private_accesser();
};

class PrivateHolder {
public:
    PrivateHolder(int val) : private_value(val) {}
    friend void Accesser::private_accesser();
private:
    int private_value;
};

void Accesser::private_accesser() {
    PrivateHolder ph(10);
    // OK: this method is declares as friend.
    std::cout << ph.private_value << std::endl;
}

Класс друга

Целый класс может быть объявлен другом. Объявление класса друга означает, что любой член друга может получить доступ к закрытым и защищенным членам объявляющего класса:

class Accesser {
public:
    void private_accesser1();
    void private_accesser2();
};

class PrivateHolder {
public:
    PrivateHolder(int val) : private_value(val) {}
    friend class Accesser;
private:
    int private_value;
};

void Accesser::private_accesser1() {
    PrivateHolder ph(10);
    // OK.
    std::cout << ph.private_value << std::endl;
}

void Accesser::private_accesser2() {
    PrivateHolder ph(10);
    // OK.
    std::cout << ph.private_value + 1 << std::endl;
}

Объявление класса друга не является рефлексивным. Если классы нуждаются в частном доступе в обоих направлениях, им нужны объявления друзей.

class Accesser {
public:
    void private_accesser1();
    void private_accesser2();
private:
    int private_value = 0;
};

class PrivateHolder {
public:
    PrivateHolder(int val) : private_value(val) {}
    // Accesser is a friend of PrivateHolder
    friend class Accesser;
    void reverse_accesse() {
        // but PrivateHolder cannot access Accesser's members.
        Accesser a;
        std::cout << a.private_value;
    }
private:
    int private_value;
};


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow