Menu
Coddy logo textTech

Спецификаторы доступа в C++

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

C++ предоставляет три спецификатора доступа, которые управляют тем, кто может обращаться к членам класса: public, protected и private. Они составляют основу инкапсуляции.

class Account {
public:
    std::string ownerName;      // Доступно отовсюду
    
protected:
    double interestRate;        // Доступно в этом классе и производных классах
    
private:
    double balance;             // Доступно только внутри этого класса
};

Public члены доступны отовсюду — внутри класса, из производных классов и из внешнего кода. Private члены являются наиболее строгими и доступны только внутри самого класса. Protected занимает промежуточное положение — он действует как private для внешнего мира, но производные классы могут обращаться к этим членам.

class Account {
private:
    double balance;
    
public:
    Account() : balance(0) {}
    
    void deposit(double amount) {
        balance += amount;    // OK - внутри класса
    }
};

int main() {
    Account acc;
    acc.deposit(100);         // OK - deposit является публичным (public)
    // acc.balance = 500;     // ОШИБКА - balance является приватным (private)
}

По умолчанию все члены класса являются private, если не указан спецификатор доступа. Это побуждает вас явно решать, что должно быть открыто. Общепринятая практика заключается в том, чтобы делать члены данных private и предоставлять public методы для безопасного взаимодействия с ними.

challenge icon

Задание

Легко

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

Вы создадите два файла для организации своего кода:

  • Employee.h: Определите класс Employee, который использует все три спецификатора доступа для соответствующей защиты данных:
    • Public: name сотрудника (string) — к нему можно получить доступ откуда угодно
    • Protected: department сотрудника (string) — доступен внутри класса и производным классам, но не извне
    • Private: salary сотрудника (double) — доступен только внутри самого класса
    • Конструктор, который принимает name, department и salary для инициализации всех трех членов
    • Публичный метод getSalary(), который возвращает значение приватной зарплаты
    • Публичный метод getDepartment(), который возвращает значение защищенного отдела
    • Публичный метод giveRaise(double amount), который увеличивает зарплату на заданную сумму (только если сумма положительная)
    • Публичный метод displayInfo(), который выводит информацию о сотруднике в формате: "Name: <name>, Department: <department>, Salary: "Name: <name>, Department: <department>, Salary: $<salary>"lt;salary>"
  • main.cpp: Продемонстрируйте работу спецификаторов доступа, взаимодействуя с объектом Employee. Считайте имя, отдел и зарплату сотрудника из входных данных (три отдельные строки), затем:
    • Создайте объект Employee с входными значениями
    • Выведите имя сотрудника напрямую, обратившись к публичному члену: "Direct access - Name: <name>"
    • Выведите отдел, используя геттер: "Via getter - Department: <department>"
    • Выведите зарплату, используя геттер: "Via getter - Salary: "Via getter - Salary: $<salary>"lt;salary>"
    • Дайте сотруднику прибавку в размере 5000.0
    • Выведите "After raise:"
    • Вызовите displayInfo(), чтобы показать обновленную информацию

Форматируйте все значения зарплаты с двумя знаками после запятой, используя std::fixed и std::setprecision(2) из <iomanip>. Преобразуйте входную строку зарплаты в double с помощью std::stod().

Ключевая идея здесь заключается в том, что хотя вы можете получить доступ к name напрямую из main, вы не можете получить прямой доступ к department или salary — вы должны использовать публичные методы-геттеры. Это инкапсуляция в действии: класс контролирует, как его данные просматриваются и изменяются.

Шпаргалка

C++ предоставляет три спецификатора доступа для управления доступом к членам класса:

  • public: Доступен отовсюду
  • protected: Доступен внутри класса и производных классов
  • private: Доступен только внутри самого класса
class Account {
public:
    std::string ownerName;      // Доступен отовсюду
    
protected:
    double interestRate;        // Доступен в этом классе и производных классах
    
private:
    double balance;             // Доступен только внутри этого класса
};

По умолчанию все члены класса являются private, если спецификатор не указан.

Пример, демонстрирующий управление доступом:

class Account {
private:
    double balance;
    
public:
    Account() : balance(0) {}
    
    void deposit(double amount) {
        balance += amount;    // OK - внутри класса
    }
};

int main() {
    Account acc;
    acc.deposit(100);         // OK - deposit является public
    // acc.balance = 500;     // ОШИБКА - balance является private
}

Лучшая практика: делайте поля данных private и предоставляйте публичные методы для безопасного взаимодействия с ними.

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

#include <iostream>
#include <string>
#include <iomanip>
#include "Employee.h"

using namespace std;

int main() {
    // Чтение входных данных
    string name;
    string department;
    string salaryStr;
    
    getline(cin, name);
    getline(cin, department);
    getline(cin, salaryStr);
    double salary = stod(salaryStr);
    
    // Установка точности для вывода зарплаты
    cout << fixed << setprecision(2);
    
    // TODO: Создать объект Employee с входными значениями
    
    // TODO: Вывести имя сотрудника, обратившись к публичному члену напрямую
    // Формат: "Direct access - Name: <name>"
    
    // TODO: Вывести отдел, используя метод-геттер
    // Формат: "Via getter - Department: <department>"
    
    // TODO: Вывести зарплату, используя метод-геттер
    // Формат: "Via getter - Salary: $<salary>"
    
    // TODO: Увеличить зарплату сотрудника на 5000.0
    
    // TODO: Вывести "After raise:"
    
    // TODO: Вызвать displayInfo() для отображения обновленной информации
    
    return 0;
}
quiz iconПроверьте себя

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

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