Спецификаторы доступа в 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 методы для безопасного взаимодействия с ними.
Задание
ЛегкоДавайте создадим простую систему управления сотрудниками, которая демонстрирует, как спецификаторы доступа контролируют, кто и к чему может иметь доступ. Вы создадите класс, в котором некоторые данные полностью приватны, некоторые доступны потенциальным подклассам, а некоторые открыты для всех.
Вы создадите два файла для организации своего кода:
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>"
- Public:
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;
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыСборка и компиляция C++Заголовочные файлы и файлы исходного кодаПространства имен и область видимостиВведение в ООП на C++Классы и объектыУказатель 'this'Методы (функции-члены)Атрибуты (члены данных)Основы конструкторов и деструкторовИтоги — Простой калькулятор4Свойства классов
Члены экземпляра против статическихГеттеры и сеттерыКонстантные функции-членыКлючевое слово mutableСтатические методы и переменныеДружественные функции и классыИтоги — Менеджер банковских счетов7Наследование
Основы наследованияУровни доступа при наследованииПорядок вызова конструкторов и деструкторовПереопределение методовВиртуальные функции и VTableМножественное наследованиеВиртуальное наследованиеИтоги — Иерархия сотрудников10Обзор STL
Обзор и философия STLКонтейнеры STLИтераторыАлгоритмы STLФункторы и лямбда-выраженияИтоги: частота слов13Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonFactory и Abstract FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy2Управление памятью
Стек и кучаУказатели и ссылкиДинамическая память (new/delete)Умные указатели в C++RAII в C++Итоги — Менеджер динамического массива5Инкапсуляция
Спецификаторы доступа в C++Спецификаторы доступа: подробный разборСокрытие данныхStruct против ClassВложенные и внутренние классыИтоги — Система учета студентов8Полиморфизм
Полиморфизм компиляции и времени выполненияПерегрузка функцийВиртуальные функции: повторениеЧистые виртуальные функцииАбстрактные классыПроектирование интерфейсов на C++Dynamic Casting и RTTIИтоги: Калькулятор фигур11Продвинутые концепции ООП
Композиция против наследованияМиксины через CRTPИдиома PimplСтирание типовEnum Classes и строгая типизацияОбработка исключений в ООППользовательские иерархии исключений14Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикRAII как паттерн3Конструкторы и деструкторы
Конструктор по умолчаниюПараметризованный конструкторКонструктор копированияКонструктор перемещенияСписки инициализации конструктораДелегирующие конструкторыГлубокое погружение в деструкторыПравило трех / пяти / нуляПовторение — класс String6Перегрузка операторов
Введение в перегрузку операторовПерегрузка арифметических операторовПерегрузка операторов сравненияОператоры потоковПерегрузка оператора присваиванияПерегрузка операторов [] и ()Операторы преобразования типовИтоги — класс Matrix9Шаблоны
Шаблоны функцийШаблоны классовСпециализация шаблоновВариативные шаблоныОсновы SFINAE и Type TraitsИтоги — Обобщенный контейнер