Menu
Coddy logo textTech

Дружественные функции и классы

Часть раздела Объектно-ориентированное программирование путешествия по C++ на Coddy. Урок 32 из 104.

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

friend function объявляется внутри class, но не является членом этого class. Она может получать доступ к закрытым и защищённым членам class:

class Box {
    double width;
    
public:
    Box(double w) : width(w) {}
    
    // Объявить printWidth как friend
    friend void printWidth(const Box& b);
};

// Определение friend-функции — НЕ функция-член
void printWidth(const Box& b) {
    std::cout << b.width;    // Может получить доступ к private-члену
}

Обратите внимание, что printWidth определена вне класса без оператора разрешения области видимости. Это обычная function, у которой случайно есть специальные права доступа.

Вы также можете сделать целый class friend, предоставив всем его member function access к закрытым member:

class Engine {
    int horsepower;
    
    friend class Mechanic;    // Mechanic может получать доступ к приватным членам
    
public:
    Engine(int hp) : horsepower(hp) {}
};

class Mechanic {
public:
    void diagnose(const Engine& e) {
        std::cout << e.horsepower;    // Разрешено - Mechanic является другом
    }
};

Дружба не является взаимной: если Engine объявляет Mechanic как friend, Mechanic может получать доступ к закрытым members Engine, но не наоборот. Используй friend умеренно, поскольку он создаёт тесную связанность между классами. Чаще всего friend полезен для перегрузки operator и тесно связанных вспомогательных function.

challenge icon

Задание

Легко

Давайте создадим безопасную систему обмена сообщениями, в которой MessageReader class нужен специальный доступ для чтения зашифрованных сообщений, хранящихся в SecureMessage class. Это идеальный сценарий для использования friend functions и friend classes.

Вы создадите два файла, чтобы организовать свой код:

  • SecureMessage.h: Define SecureMessage class, который хранит private данные сообщения и предоставляет выборочный доступ доверенным сущностям. Ваш class должен содержать:
    • Private members: content (string) и secretKey (int)
    • constructor, принимающий content и secret key
    • Declare MessageReader как friend class, чтобы он мог обращаться к private members
    • Declare friend function decryptMessage(const SecureMessage& msg, int key), которая возвращает content только в том случае, если переданный key совпадает с secret key, иначе возвращает "Access Denied"

    Затем define MessageReader class в том же header-файле:

    • method readContent(const SecureMessage& msg), который напрямую обращается к private content сообщения и возвращает его
    • method verifyKey(const SecureMessage& msg, int key), который проверяет, совпадает ли переданный key с secretKey сообщения, и возвращает "Valid" или "Invalid"

    Наконец, define friend function decryptMessage после classes.

  • main.cpp: Продемонстрируйте работу friend functions и friend classes. Прочитайте из input content сообщения, secret key и test key (каждый с отдельной строки), затем:
    • Create SecureMessage с content и secret key
    • Create MessageReader object
    • Выведите "Reader access: <content>" с помощью method readContent() reader
    • Выведите "Key verification: <result>" с помощью verifyKey() и test key
    • Выведите "Decrypt with test key: <result>" с помощью friend function и test key
    • Выведите "Decrypt with correct key: <result>" с помощью friend function и исходного secret key

Помните, что friend functions определяются за пределами class без оператора разрешения области видимости: это обычные functions с особыми правами доступа. MessageReader class, являясь friend, может напрямую обращаться к private members SecureMessage во всех своих methods.

Преобразуйте key, полученные из input, из строк в целые числа с помощью std::stoi(). Подключите header-файл в main.cpp с помощью #include "SecureMessage.h".

Попробуйте сами

#include <iostream>
#include <string>
#include "SecureMessage.h"
using namespace std;

int main() {
    // Читать ввод
    string messageContent;
    string secretKeyStr;
    string testKeyStr;
    
    getline(cin, messageContent);
    getline(cin, secretKeyStr);
    getline(cin, testKeyStr);
    
    int secretKey = stoi(secretKeyStr);
    int testKey = stoi(testKeyStr);
    
    // TODO: Создать SecureMessage с содержимым и секретным ключом
    
    // TODO: Создать объект MessageReader
    
    // TODO: Print "Reader access: <content>" using readContent()
    
    // TODO: Print "Key verification: <result>" using verifyKey() with test key
    
    // TODO: Print "Decrypt with test key: <result>" using decryptMessage with test key
    
    // TODO: Print "Decrypt with correct key: <result>" using decryptMessage with secret key
    
    return 0;
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор C++